home *** CD-ROM | disk | FTP | other *** search
/ Best of Shareware / Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso / mac / ZIPPED / DOS / GRAPHICS / POVSRC.ZIP / MACHINE.ZIP / MAC.SIT / pov.c < prev    next >
C/C++ Source or Header  |  1992-06-24  |  106KB  |  4,127 lines

  1. /****************************************************************************
  2. *                POV.c
  3. *
  4. *  This file contains Macintosh-specific routines for Persistence Of Vision
  5. *  raytracer (POV-Ray.)
  6. *
  7. *     This Macintosh version of POV-Ray was created and compiled by Jim Nitchals
  8. *   (Think 5.0) and Eduard Schwan (MPW), based very loosely on the original
  9. *   ports by Thomas Okken and David Lichtman with some help from Glenn Sugden.
  10. *
  11. *    For bug reports regarding the Mac version specifics ONLY, go ahead and
  12. *    contact Jim Nitchals at Compuserve: 73117,3020 or America Online: JIMN8.
  13. *   Look for forum support on America Online's Mac Graphics forum Company
  14. *   Support area, or Compuserve's Computer Art (COMART) forum.
  15. *    
  16. *  from Persistence of Vision Raytracer 
  17. *  Copyright 1991-1992 Persistence of Vision Team
  18. *---------------------------------------------------------------------------
  19. *  Copying, distribution and legal info is in the file povlegal.doc which
  20. *  should be distributed with this file. If povlegal.doc is not available
  21. *  or for more information please contact:
  22. *
  23. *       Drew Wells [POV-Team Leader] 
  24. *       CIS: 73767,1244  Internet: 73767.1244@compuserve.com
  25. *       Phone: (213) 254-4041
  26. * This program is based on the popular DKB raytracer version 2.12.
  27. * DKBTrace was originally written by David K. Buck.
  28. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  29.  
  30. */
  31.  
  32. /* Standard C headers */
  33. #include <stdlib.h>
  34. #include <setjmp.h>
  35.  
  36. #include "frame.h"
  37. #include "povproto.h"
  38.  
  39.  
  40. /* Macintosh-specific headers */
  41. #include <Controls.h>
  42. #include <Desk.h>
  43. #include <Dialogs.h>
  44. #include <Files.h>
  45. #include <Memory.h>
  46. #include <Menus.h>
  47. #include <OSEvents.h>
  48. #include <OSUtils.h>
  49. #include <Packages.h>
  50. #include <QuickDraw.h>
  51. #include <Resources.h>
  52. #include <Types.h>
  53. #include <Windows.h>
  54. #include <scrap.h>
  55. #include <shutdown.h>
  56. #include <sound.h>
  57. #include <AppleEvents.h>
  58. #include <GestaltEqu.h>
  59. #include <Folders.h>
  60. #include <errors.h>            /* dupFNErr, etc */
  61. #include <fonts.h>
  62. #include <segload.h>        /*UnloadSeg*/
  63. #include <eppc.h>            /* kHighLevelEvent */
  64. #include <traps.h>            /* _Unimplemented */
  65. #ifdef applec
  66. #include <strings.h>        /*p2cstr*/
  67. #endif
  68. #include <string.h>            /*strcpy/cat*/
  69. #include <toolutils.h>        /* BitTst, etc */
  70.  
  71. /* MPW Performance tool code */
  72. #ifdef applec
  73. #ifdef NEEDS_PERF
  74. #include <perf.h>
  75. #endif NEEDS_PERF
  76. #endif applec
  77.  
  78. #include    "SaveCmpPict.h"
  79.  
  80.  
  81. #include "POVMac.h"            /* includes function prototypes */
  82.  
  83. /* printf capture window */
  84. #include "printf2window.h"
  85.  
  86. /* These #defines map Think C names into their MPW C equivalent */
  87. #ifdef applec
  88. #define CtoPstr    c2pstr
  89. #define PtoCstr    p2cstr
  90. #define OK        ok
  91. #define Cancel    cancel
  92. #endif applec
  93.  
  94. #define reserveMemSize    80000L    /* out-of-mem reserve space */
  95.  
  96. #define _QD32Trap 0xAB03 /* 32 bit Quickdraw trap */
  97.  
  98. /* keyboard values used by ModalFilter() */
  99. #define kReturnKey        0x0D
  100. #define kEnterKey        0x03
  101. #define kEscKey            0x1B
  102. #define kTabKey            0x09
  103.  
  104. /* All dialogs have a user item #3 for outlining buttons */
  105. #define kDefaultItem    3
  106.  
  107. /* Dialog resource IDs */
  108. #define    kdlog_P2W_INIT_ERROR    9601
  109. #define    kdlog_TOO_MANY_FILES    151
  110.  
  111. #define    kMinMultiFriendly    1
  112. #define    kDefMultiFriendly    4
  113. #define    kMaxMultiFriendly    15
  114.  
  115. /* The Finder Events Suite - defined in the not-yet-existing <AERegistry.h> */
  116. #define kAEFinderEvents 'FNDR'
  117.  
  118.  
  119. #ifdef applec
  120. /* entry point to %a5init segment, for disposal after init */
  121. extern void _DataInit();
  122.  
  123. #ifdef NEEDS_PERF
  124. TP2PerfGlobals    ThePGlobals;    /* performance globals rec */
  125. #endif NEEDS_PERF
  126. #endif applec
  127.  
  128. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* POV-Ray externals *-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  129. extern void alt_main(short argc, char **argv);
  130. volatile extern int Stop_Flag;
  131. extern int token_count, line_count;
  132. extern DBL Max_Trace_Level;
  133. extern COLOUR_MAP_ENTRY *Construction_Map;
  134. extern int Targa_Line_Number;
  135.  
  136. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  137.  
  138.  
  139. /* Externals from the text editor */
  140. extern pascal void ScrollProc (ControlHandle theControl, short theCode);
  141. // extern pascal void ScrollProc (ControlHandle theControl, int theCode);
  142. extern WindowRecord        wRecord;
  143. extern WindowPtr        TextEditWindow;
  144. extern TEHandle            TEH;
  145. extern char                dirty;
  146. extern ControlHandle     vScroll;
  147. extern char                window_visible;
  148. extern Str255             theFileName;
  149. extern short            theVRefNum;
  150. extern Cursor            waitCursor;
  151.  
  152. #define    PICTF_HEADER_SIZE    512        // old MacDraw PICTF header
  153.  
  154. /* Pict file header structure (after the 512 byte header) */
  155. typedef struct
  156. {
  157.     short        picSize;        // low word of size
  158.     Rect        picFrame;        // picture bounds
  159. } PictFHeader, *PictFHeaderPtr;
  160.  
  161. PicHandle    myPicHandle;    // used by Paint_to_Picture() and MyPutPicProc()
  162. long        myPicSize;        // used by Paint_to_Picture() and MyPutPicProc()
  163.  
  164. jmp_buf        env;
  165. int            POV_running = 0;    /* Used to determine the menu states. */
  166.  
  167. int            ARGC;
  168. char        *ARGV[32], argstr[1024], *argptr;
  169.  
  170. short        ourRefNum, prefsRefNum, fileResRefNum;
  171. char        targaOutName[256];    /* name of Targa output file */
  172. PixMapHandle pm;
  173. WindowPtr    plot_window = NULL;
  174. Ptr            plot_pixmap = NULL;
  175. Ptr            undo_buffer = NULL;
  176. Ptr            undo_buffer2 = NULL;
  177. Ptr            revert_buffer = NULL;
  178.  
  179. long        global_bufsize;
  180.  
  181. short        undoable = 0;        /* can we undo this operation? */
  182.  
  183. short        backgrounding = 0;    /* is the program currently backgrounded? */
  184. short        do_notify = 0;        /* inform user of completed trace */
  185. Rect        plot_bounds, disp_plot_bounds;
  186. short        global_width, global_height, global_y;
  187.  
  188. int            in_parse = 0;        /* track malloc() and free() during parse only! */
  189. long        MyTickCount = 0;    /* Time of last Event manager call */
  190. long        MyRefreshCount = 0; /* Time of last Quickdraw dither of graphic port */
  191. int            lastDrawnY = 0;        /* last vertical position during previous refresh */
  192. int            WNEavailable = 0;     /* Running under MultiFinder or System 7? */
  193. int            Gestalt_Available = 0;    /* Gestalt available? */
  194. int            AppleEvents_Available = 0; /* Apple Events available for doing shutdown? */
  195. int            qd32_Available = 0; /* is 32 bit Quickdraw available for depth & dithering */
  196. int            ImageCompressionMgrAvailable=0; /* Is QuickTime available? */
  197. long        MultiFriendly = 0;
  198. long        ditherTime = 360;
  199. long        startupMessageTime = 0;
  200. short        display_magniFactor = 1;
  201. Boolean        doPictCompression = false;
  202.  
  203. FILE        *virtual_file = 0;
  204. FILE        *savePICT_file = 0;
  205. short        virtual_pixHeight = 0;
  206. short        virtual_bufferDirty = 0;
  207. short        virtual_currentSegment = 0;
  208. short        virtual_minY = 0;
  209. short        virtual_maxY = 0;
  210. long        virtual_segSize = SWAP_SIZE;
  211.  
  212. MenuHandle    myMenus[highest_menu+1];
  213. MenuHandle    mySubMenus[highest_submenu+1];
  214. RgnHandle    theUpdateRgn;
  215. char        run_flag = 0, quit_flag = 0;
  216. EventRecord    myEvent;
  217. long         prev_upd_plot;
  218.  
  219. prefs_ptr_t    global_settings;
  220. prefs_hdl_t    global_settings_h;
  221. prefs_ptr_t    file_settings;
  222. prefs_hdl_t    file_settings_h;
  223.  
  224. short        pause_flag = 0;
  225. short        itemHit;
  226. short        enable_return_key;
  227. DialogPtr    myDialog = NULL;
  228. DialogPtr    startupScreen = NULL;
  229. Handle        extra_dialog_RAM;
  230.  
  231. short        rendered_OK;
  232. int            first_time_thru = true;
  233. char        c_theFileName[255];
  234. long        TargetTicks;
  235. long        mallocCount, mfreeCount, maxmalloc;
  236. long        *GarbagePile, *RecycledPile;
  237. p2w_WindowPtr        myp2window = NULL;
  238. Boolean        myp2windowIsUp = false;
  239. Rect        dragBounds;
  240.  
  241. /* QuickTime stuff */
  242. ComponentInstance    gtheSCComponent = NULL;    
  243. SCParams            gSCDialogParams;
  244.  
  245. /* text editor undo support */
  246.  
  247. typedef struct
  248. {
  249.     char    *buffer;
  250.     char    **buf_handle;
  251.     short    dirty;
  252.     long    byteCount, selStart, selEnd;
  253.     char    reason[127];
  254. } undoStruct;
  255.  
  256. #define        max_undo 16
  257. int            undoCount;
  258. char        undo_menu_name[127], redo_menu_name[127];
  259. int            undo_key_copied;
  260. undoStruct    undo_record[max_undo+1];
  261. undoStruct    redo_record[max_undo+1];
  262.  
  263. /* Undefine the malloc and free calls now */
  264. #undef malloc
  265. #undef free
  266. #undef calloc
  267.  
  268. /* NewPtr is too slow.  Think's memory system is nice 'n fast.       */
  269. /* Consider using handles and locking them-- also faster than NewPtr */
  270. void *POV_malloc(size_t size)
  271. {
  272.     void *myptr = NULL;
  273. TRY_TO_ALLOCATE:
  274.     if (extra_dialog_RAM != NULL)
  275.         myptr = malloc(size);
  276.     if (myptr == 0)
  277.     {
  278.         if (free_undo_memory())
  279.             goto TRY_TO_ALLOCATE;
  280.         /* if there's any other RAM we can squeeze, now's the time. */
  281.         if (extra_dialog_RAM)                    
  282.         {
  283.             DisposeHandle(extra_dialog_RAM);
  284.             extra_dialog_RAM = NULL;
  285.         }
  286.     }
  287.     else
  288.         if (in_parse)
  289.         {
  290.             GarbagePile[mallocCount] = (long) myptr;
  291.             if (mallocCount < maxmalloc)
  292.                 mallocCount++;
  293.         }
  294.     return myptr;
  295. }
  296.  
  297. void *POV_calloc(size_t nmemb, size_t size)
  298. {
  299.     void *myptr = NULL;
  300. TRY_TO_ALLOCATE:
  301.     if (extra_dialog_RAM != NULL)
  302.         myptr = calloc(nmemb, size);
  303.     if (myptr == 0)
  304.     {
  305.         if (free_undo_memory())
  306.             goto TRY_TO_ALLOCATE;
  307.         /* if there's any other RAM we can squeeze, now's the time. */
  308.         if (extra_dialog_RAM)                    
  309.         {                                        
  310.             DisposeHandle(extra_dialog_RAM);    
  311.             extra_dialog_RAM = NULL;            
  312.         }
  313.     }
  314.     else
  315.         if (in_parse)
  316.         {
  317.             GarbagePile[mallocCount] = (long) myptr;
  318.             if (mallocCount < maxmalloc)
  319.                 mallocCount++;
  320.         }
  321.     return myptr;
  322. }
  323.  
  324. void POV_free(void *ptr)
  325. {
  326.     if (in_parse == 0)
  327.     {
  328.         free(ptr);
  329.         return;
  330.     }
  331.     if (ptr)
  332.     {
  333.         free(ptr);
  334.         RecycledPile[mfreeCount] = (long) ptr;
  335.         if (mfreeCount < maxmalloc)
  336.             mfreeCount++;
  337.     }
  338. }
  339.  
  340. // included in case of future inclusion by POV-Ray main
  341. void getch(void)
  342. {
  343. // part of "usage" message printing in POVRay.C
  344. }
  345.  
  346. void Collect_Garbage(void)
  347. {
  348.     long i, j, k;
  349.     long the_item;
  350.     long *trashSorter;
  351.  
  352.     in_parse = 1;
  353.     if (mallocCount == 0) return;
  354.     DisableMenus();
  355.     SetCursor(&waitCursor);
  356.     k = mallocCount;
  357. /* malloc and mfree's are in chronological order.  The first matching item 
  358. in the malloc list is always the correct one for the first occurrence in the mfree list. */ 
  359.  
  360.     if (mfreeCount)
  361.     {
  362.         for (i=0; i<mfreeCount; i++)
  363.         {
  364.             the_item = RecycledPile[i];
  365.             trashSorter = GarbagePile;
  366.             for (j = 0; j<k; j++)
  367.             {
  368.                 if (*trashSorter++ == the_item)
  369.                 {
  370.                     --trashSorter;
  371.                     *trashSorter = 0;
  372.                     goto ALREADY_FREE;
  373.                 }
  374.             }
  375.     ALREADY_FREE:
  376.             Cooperate();
  377.         }
  378.     }
  379.  
  380.     for (i=0; i<mallocCount; i++)
  381.     {
  382.         if (GarbagePile[i])
  383.             free((void *) GarbagePile[i]);
  384.         Cooperate();
  385.     }
  386.     printf("Done releasing memory.\n");
  387.     mallocCount = 0;
  388.     mfreeCount = 0;
  389.     *GarbagePile = 0;
  390.     *RecycledPile = 0;
  391.     EnableMenus();
  392.     SetCursor(&qd.arrow);
  393. }
  394.  
  395. void restore_state(void)
  396. {
  397.     rendered_OK = 0;
  398.     longjmp(env, 1);
  399. }
  400.  
  401.  
  402. int    first_time_called(void)
  403. {
  404.     int a;
  405.     a = first_time_thru;
  406.     first_time_thru = false;
  407.     return (a);
  408. }
  409.  
  410. #ifdef NEEDS_PERF
  411.  
  412. void startPerf(void)
  413. {
  414.     /* Initialize the performance globals */
  415.     ThePGlobals = nil;
  416.     if (!InitPerf(&ThePGlobals,
  417.                 4,                        /* ms */
  418.                 8,                        /* bytes */
  419.                 true,                    /* measure ROM code */
  420.                 true,                    /* measure application code */
  421.                 (StringPtr)"\pCODE",    /* segments to measure */
  422.                 0,                        /* Let the performance tools calculate the ROM id */
  423.                 (StringPtr)"\p",        /* Let the performance tools find the ROM name */
  424.                 true,                    /* measure RAM? */
  425.                 0,                        /* low RAM address */
  426.                 0x0FFFFF,                /* high RAM address */
  427.                 16                        /* RAM bucket size */
  428.                 ))
  429.     {
  430.         SysBeep(4);    /* error */
  431. //        displayDialog(rErrorID,"Errors starting Performance Dump!");
  432. //        exit(1);    /* error */
  433.     }
  434. }
  435.  
  436.  
  437. void doPerf(short perfFlag)
  438. {
  439.     PerfControl(ThePGlobals, perfFlag);    /* turn on/off measurements */
  440. } /* doPerf */
  441.  
  442.  
  443. void stopPerf(void)
  444. {
  445.     /* Write the performance raw data into a file */
  446. /* NOTE: IN MPW 3.2, YOU WILL CRASH HORRIBLY IF YOU TURN ON/OFF Perf TWICE! */
  447. /*    doPerf(false);    /* make sure everything is turned off */
  448.     if (PerfDump(ThePGlobals, (StringPtr)"\pPOVPerf.out", true, 80) )
  449.     {
  450.         SysBeep(4);    /* error */
  451. //        displayDialog(rErrorID,"Errors while saving Performance Dump!");
  452.     }
  453.     TermPerf(ThePGlobals);    /* clean up */
  454. }
  455.  
  456. #endif NEEDS_PERF
  457.  
  458.  
  459. void get_WindowPos(WindowPtr theWindow, Rect *theRect)
  460. {
  461.     Rect    windRect;
  462.  
  463.     windRect = theWindow->portRect;
  464.  
  465.     // yah, but where is it really?
  466.     SetPort(theWindow);
  467.     LocalToGlobal((Point*)&windRect.top);
  468.     LocalToGlobal((Point*)&windRect.bottom);
  469.  
  470.     *theRect = windRect;
  471. }
  472.  
  473. void forceRectOnScreen(Rect *aGlobalRect)
  474. {
  475.     long        area;
  476.     long        foundArea;
  477.     GDHandle    aDevice;
  478.     GDHandle    foundDevice;
  479.     Rect        aDeviceRect;
  480.     Rect        intersectRect;
  481.  
  482.     /* Use main device as default choice, in case no match found */
  483.     foundDevice = GetMainDevice();
  484.     aDeviceRect = (**foundDevice).gdRect;
  485.     SectRect(aGlobalRect, &aDeviceRect, &intersectRect);
  486.     foundArea = 0;
  487.  
  488.     for (aDevice = GetDeviceList(); aDevice; aDevice = GetNextDevice(aDevice))
  489.     {
  490.         /* If we found an active screen device that intersects some of the rect.. */
  491.         aDeviceRect = (**aDevice).gdRect;
  492.         if (TestDeviceAttribute(aDevice, screenDevice)
  493.             && TestDeviceAttribute(aDevice, screenActive)
  494.             && SectRect(aGlobalRect, &aDeviceRect, &intersectRect))
  495.         {
  496.             /* find out how much it intersects */
  497.             area = (intersectRect.right - intersectRect.left) *
  498.                    (intersectRect.bottom - intersectRect.top);
  499.             /* if intersects more than the last device of intersection, use this instead */
  500.             /* this therefore finds the screen of greatest intersection */
  501.             if (area > foundArea)
  502.             {
  503.                 foundDevice = aDevice;
  504.                 foundArea = area;
  505.             }
  506.         }
  507.     }
  508.  
  509.     /* OK, we have now travelled through all the devices, and 'foundDevice' */
  510.     /* will have the best device to use, or the main device if there was    */
  511.     /* no intersecting screens at all.. Make sure it fits on the screen        */
  512.  
  513.     /* If there is not enough area showing, or top of rect is off screen..    */
  514.     /* then move the window to better position on 'foundDevice'                */
  515.     if ( (foundArea < 200) || (aGlobalRect->top < (**foundDevice).gdRect.top) )
  516.     {
  517.         /* adjust gdRect to size of aGlobalRect, & offset it a little */
  518.         aDeviceRect = (**foundDevice).gdRect;
  519.         OffsetRect(&aDeviceRect, 10, 40);
  520.         aDeviceRect.right = aDeviceRect.left + (aGlobalRect->right - aGlobalRect->left);
  521.         aDeviceRect.bottom = aDeviceRect.top + (aGlobalRect->bottom - aGlobalRect->top);
  522.         /* Return this rect as the one to use */
  523.         *aGlobalRect = aDeviceRect;
  524.     }
  525. } // forceRectOnScreen
  526.  
  527.  
  528.  
  529. short trapAvailable(short tNumber, TrapType tType, SysEnvRec *seRec)
  530. {
  531.     if    (
  532.             (tType == (unsigned char) ToolTrap) &&
  533.             (seRec->machineType > envMachUnknown) &&
  534.             (seRec->machineType < envMacII)
  535.         )
  536.         {    /* it's a 512KE, Plus, or SE */
  537.         tNumber = tNumber & 0x03FF;
  538.         if (tNumber > 0x01FF)                /* which means the tool traps */
  539.             tNumber = _Unimplemented;        /* only go to 0x01FF */
  540.         }
  541.     return (NGetTrapAddress(tNumber, tType)
  542.             != NGetTrapAddress(_Unimplemented, ToolTrap));
  543. } /*trapAvailable()*/
  544.  
  545.  
  546. pascal void outlineDefaultButton(DialogPtr theDialog, short theItem)
  547. {
  548.     PenState    SavePen;
  549.     short        itemType;
  550.     Handle        itemHandle;
  551.     Rect        dispRect;
  552. #pragma unused (theItem)
  553.  
  554.     GetPenState(&SavePen);
  555.     /* use 'ok' (#1) item's rectangle */
  556.     GetDItem(theDialog, OK, &itemType, &itemHandle, &dispRect);
  557.     SetPort(theDialog);
  558.     PenSize(3, 3);
  559.     InsetRect(&dispRect, -4, -4);
  560.     FrameRoundRect(&dispRect, 16, 16);
  561.     SetPenState(&SavePen);
  562. } // outlineDefaultButton
  563.  
  564.  
  565. /* Grabs the ControlHandle for the item in the dialog box */
  566. ControlHandle GrabDItemHandle(DialogPtr theDialog, short theGetItem)
  567. {
  568.     short    itemtype;
  569.     Rect    itemrect;
  570.     Handle    tempHandle;
  571.     
  572.     GetDItem(theDialog, theGetItem, &itemtype, &tempHandle, &itemrect);
  573.     return((ControlHandle)tempHandle);
  574. } // GrabDItemHandle
  575.  
  576.  
  577. /* Sets dialog's #1 item's display proc to draw outline */
  578. void SetupDefaultButton(DialogPtr theDialog)
  579. {
  580.     short    itemtype;
  581.     Rect    itemrect;
  582.     Handle    tempHandle;
  583.  
  584.     /* Set up User item (always #3) to display a border around OK button (#1) */
  585.     GetDItem(theDialog, kDefaultItem, &itemtype, &tempHandle, &itemrect);
  586.     SetDItem(theDialog, kDefaultItem, itemtype, (Handle)&outlineDefaultButton, &itemrect);
  587.     enable_return_key = 1;    // enable the Return key for "OK" by default.
  588. } // SetupDefaultButton
  589.  
  590.  
  591. pascal Boolean ModalFilter(DialogPtr theDialog, EventRecord *theDialogEvent, short *theDialogItem)
  592. {
  593.     WindowPtr tempGP;
  594.     char theKey;
  595.     long tilticks;
  596.     Boolean returnVal = false; // not yet handled
  597.  
  598.     /* remember where we parked */
  599.     GetPort(&tempGP);
  600.     SetPort(theDialog);
  601.  
  602.     /* Deal with KeyDowns */
  603.     if ((theDialogEvent->what == keyDown) || (theDialogEvent->what == autoKey))
  604.     {
  605.         theKey = theDialogEvent->message & charCodeMask;
  606.  
  607.         /* Do filtering for <ESC> and <CR> as OK and Cancel, per Human Interface guidelines. */
  608.         switch (theKey)
  609.         {
  610.             case kEnterKey:
  611.                 /* Make the Enter key identical to the Return key! */
  612.                 /* Mask out the Enter key, and OR in the Return key */
  613.                 theDialogEvent->message = (theDialogEvent->message & ~charCodeMask) | kReturnKey;
  614.             case kReturnKey:
  615.                 if (enable_return_key)
  616.                 {
  617.                     /* This filters for Return or Enter as item 1, and Esc as item 2 */
  618.                     *theDialogItem = OK;            /* change whatever the current item is to the OK item */
  619.                     /* now we need to invert the button */
  620.                     HiliteControl(GrabDItemHandle(theDialog, OK), inButton);
  621.                     Delay(8, &tilticks);            /* wait about 8 ticks so they can see it */
  622.                     HiliteControl(GrabDItemHandle(theDialog, ok), false);
  623.                     returnVal = true;
  624.                 }
  625.                 break;
  626.                 /* This filters the escape key the same as item 2 (the canx button, usually ) */
  627.             case kEscKey:
  628.                 *theDialogItem = Cancel;        /* pretend the cancel button was hit */
  629.                 HiliteControl(GrabDItemHandle(theDialog, Cancel), inButton);
  630.                 Delay(8, &tilticks);            /* wait about 8 ticks so they can see it */
  631.                 HiliteControl(GrabDItemHandle(theDialog, Cancel), false);
  632.                  returnVal = true;
  633.                 break;
  634.         } // switch
  635.     } // if keydown
  636.  
  637.     SetPort(tempGP);
  638.  
  639.     return(returnVal);
  640.  
  641. } // ModalFilter
  642.  
  643.  
  644. OSErr GotRequiredParams(AppleEvent    *theAppleEvent)
  645. {
  646.     DescType    typeCode;
  647.     Size        actualSize;
  648.     OSErr        err;
  649.  
  650.     err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
  651.                             &typeCode, NULL, 0, &actualSize);    /* NULL ok here; need only function result */
  652.     if (err == errAEDescNotFound)
  653.         // we got all the required params: all is ok
  654.         return noErr;
  655.     else if (err == noErr)
  656.         // found one left behind: error!
  657.         return errAEEventNotHandled;
  658.     else
  659.         // some other oddity
  660.         return err;
  661. } // GotRequiredParams
  662.  
  663.  
  664. pascal OSErr HandleOapp (AEDescList *aevt, AEDescList *reply, long refCon)
  665. {
  666. #pragma unused (reply,refCon)
  667.     OSErr    anError;
  668.  
  669.     /* We don't normally expect any parms, but check in case the client requires any */
  670.     anError = GotRequiredParams(aevt);
  671.     if (!anError)
  672.         DoFile_New();
  673.  
  674.     /* if splash screen is up, pull it back to the front! */
  675.     if (startupScreen)
  676.     {
  677.         SelectWindow(startupScreen);
  678.         DrawDialog(startupScreen);
  679.     }
  680.     return anError;
  681. }
  682.  
  683. pascal OSErr HandleOdoc (AEDescList *aevt, AEDescList *reply, long refCon)
  684. {
  685. #pragma unused (reply,refCon)
  686.     OSErr        anError;
  687.     AEDesc        fileListDesc;
  688.     DescType    actualType;
  689.     long        actualSize;
  690.     AEKeyword    actualKeyword;
  691.     FSSpec        oneFile;
  692.     long        numFiles;
  693.     long        index;
  694.                         
  695.     /* The "odoc" and "pdoc" messages contain a list of aliases as the direct paramater.    */
  696.     /* This means that we'll need to extract the list, count the list's elements, and        */
  697.     /* then process each file in turn.    Return any errors to the client.                    */
  698.  
  699.     /* Extract the list of aliases into fileListDesc */
  700.     anError = AEGetParamDesc(aevt, keyDirectObject, typeAEList, &fileListDesc);
  701.  
  702.     /* Make sure that's all we're supposed to do */
  703.     if (!anError)
  704.         anError = GotRequiredParams(aevt);
  705.         
  706.     /* Count the list elements */
  707.     if (!anError)
  708.         anError = AECountItems(&fileListDesc, &numFiles);
  709.  
  710.     /* This application is rather limited for now, it just */
  711.     /* wants ONE document.  Err if more! */
  712.     if (!anError && (numFiles > 1))
  713.     {
  714.         displayDialog(kdlog_TOO_MANY_FILES, "", numFiles);
  715.         numFiles = 1; /* force the issue! */
  716.     }
  717.  
  718.     /* now get each file from the list and process it. */
  719.     /* Even though the event contains a list of aliases, the Apple Event Manager */
  720.     /* will convert each alias to an FSSpec if we ask it to. */
  721.     for (index = 1; (index <= numFiles) && !anError; index++)
  722.     {
  723.         /* Pull the Nth file out of the aevt list */
  724.         anError = AEGetNthPtr( &fileListDesc, index, typeFSS, &actualKeyword,
  725.                             &actualType, (Ptr)&oneFile, sizeof(oneFile), &actualSize);
  726.  
  727.         /* Open the File here */
  728.         if (!anError)
  729.         {
  730.             OpenTextFile(oneFile.name, oneFile.vRefNum, oneFile.parID, true/*UseDirID*/);            
  731.         }
  732.     }
  733.  
  734.     /* All done with the list, throw it away */
  735.     if (!anError)
  736.         anError = AEDisposeDesc(&fileListDesc);
  737.  
  738.     /* if splash screen is up, pull it back to the front! */
  739.     if (startupScreen)
  740.     {
  741.         SelectWindow(startupScreen);
  742.         DrawDialog(startupScreen);
  743.     }
  744.  
  745.     return anError;
  746. }
  747.  
  748.  
  749. pascal OSErr HandleQuit (AEDescList *aevt, AEDescList *reply, long refCon)
  750. {
  751. #pragma unused (reply,refCon)
  752.  
  753.     OSErr    anError;
  754.  
  755.     /* We don't normally expect any parms, but check in case the client requires any */
  756.     anError = GotRequiredParams(aevt);
  757.  
  758.     Stop_Flag = quit_flag = TRUE;
  759.     return anError;
  760. }
  761.  
  762.  
  763. void Install_AppleEvents(void)
  764. {
  765.     OSErr    err;
  766.     long    result;
  767.  
  768.     if (Gestalt_Available)
  769.     {
  770.         err = Gestalt(gestaltAppleEventsAttr, &result);
  771.         if (err == noErr) {    
  772.             AppleEvents_Available = TRUE;
  773.             (void)AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
  774.                                 (EventHandlerProcPtr)HandleOapp, 0, false);
  775.             (void)AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,   
  776.                                 (EventHandlerProcPtr)HandleOdoc, 0, false);
  777.             (void)AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,  
  778.                                 (EventHandlerProcPtr)HandleOdoc, 0, false); /* do "Print" as Open */
  779.             (void)AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
  780.                                 (EventHandlerProcPtr)HandleQuit, 0, false);
  781.         }
  782.     }
  783. }
  784.  
  785. void SendQuit(void)
  786. {
  787. OSErr        myErr;
  788. OSType        theSignature;
  789. AppleEvent    myAEvt, myReturnEvt;
  790. AEAddressDesc    myServerAddress;
  791.  
  792.     /* Still not working..! */
  793.     theSignature = 'MACS';
  794.     myErr = AECreateDesc(typeApplSignature, (Ptr)&theSignature, 4, &myServerAddress);
  795.     if (!myErr)
  796.         myErr = AECreateAppleEvent(kAEFinderEvents,            // Event Class
  797.                                     kAEShutDown,            // Event ID
  798.                                     &myServerAddress,        // Target Adr
  799.                                     kAutoGenerateReturnID,    // Return aevt ID
  800.                                     kAnyTransactionID,        // Trans ID
  801.                                     &myAEvt);                // fill me in
  802.     if (!myErr)
  803.         myErr = AESend(&myAEvt,
  804.                         &myReturnEvt,
  805.                         kAENoReply,                // send mode
  806.                         kAENormalPriority,        // send priority
  807.                         kNoTimeOut,                // N timeout ticks
  808.                         NULL,                    // idleProcPtr
  809.                         NULL);                    // EventFilterProcPtr
  810.     /* clean up before we die :-) */
  811.     if (!myErr)
  812.         myErr = AEDisposeDesc(&myServerAddress);
  813. }
  814.  
  815.  
  816. /* Returns the compiler name this code was compiled with */
  817. void GetCompilerNamePString(Str31 versionString)
  818. {
  819.     versionString[0] = '\0';
  820. #ifdef applec
  821.     pStrCopy("\pApple's MPW C", versionString);    
  822. #endif applec
  823. #ifdef THINK_C
  824.     pStrCopy("\pSymantec's Think C", versionString);    
  825. #endif THINK_C
  826. }
  827.  
  828.  
  829. /* Returns the version string in the application's version resource */
  830. void GetAppVersionPString(short versID, Str31 versionString)
  831. {
  832.     VersRecHndl    versHandle;        // VersRecHndl declared in MPW's <files.h>
  833.     
  834.     /* Get the resource string from app, 'vers' versID (1 or 2) resource! */
  835.     versionString[0] = '\0';
  836.     versHandle = (VersRecHndl)GetResource('vers',versID);
  837.     if (versHandle)
  838.         pStrCopy((**versHandle).shortVersion, versionString);
  839. }
  840.  
  841.  
  842. void displayDialog(short dlogID, char * s, short err)
  843.     {
  844.     short        itemHit;
  845.     DialogPtr    dlogp;
  846.     char        numstr[10];
  847.  
  848.     SysBeep(2);
  849.     InitCursor();
  850.  
  851.     /* convert error string to P-style */
  852.     if (s)
  853.         c2pstr(s);
  854.  
  855.     /* see if there is an error number */
  856.     numstr[0] = '\0';
  857.     if (err)
  858.         NumToString(err,numstr);
  859.  
  860.     ParamText(numstr, s, "", "");
  861.     dlogp = GetNewDialog(dlogID, (Ptr)0L, (WindowPtr)-1L);
  862.     /* "default" the OK button */
  863.     SetupDefaultButton(dlogp);
  864.     if (dlogp)
  865.         {
  866.         ModalDialog(0, &itemHit);
  867.         DisposDialog(dlogp);
  868.         }
  869.     } /*displayDialog*/
  870.  
  871.  
  872. void error_dialog(int dialognum)
  873. {
  874.     DialogPtr dlgHold;    /* allow a single level of dialog recursion */
  875.  
  876.     /* this cheap hack guarantees enough available RAM to show the error and not crash. */    
  877.     if (extra_dialog_RAM)
  878.     {
  879.         DisposeHandle(extra_dialog_RAM);
  880.         extra_dialog_RAM = 0;
  881.     }
  882.  
  883.     UseResFile(ourRefNum);
  884.     dlgHold = myDialog;
  885.     SetCursor(&qd.arrow);    /* it could still be a text cursor! */
  886.     myDialog = GetNewDialog(dialognum, NULL, (WindowPtr) -1);
  887.     if (myDialog)
  888.     {
  889.         /* "default" the OK button */
  890.         SetupDefaultButton(myDialog);
  891.         do {
  892.             ModalDialog(NULL, &itemHit);
  893.         } while (itemHit != 1);
  894.         DisposDialog(myDialog);
  895.         itemHit = -1;        /* don't send spurious item # to other dialogs! */
  896.     }
  897.     myDialog = dlgHold;
  898.     if (FreeMem() > reserveMemSize)
  899.         extra_dialog_RAM = NewHandle(reserveMemSize);
  900. }
  901.  
  902. /* --- These are required routines from machine.h --- */
  903.  
  904. void display_finished(void)
  905. {
  906. }
  907.  
  908. void display_close(void)
  909. {
  910. }
  911.  
  912. void open_virtual(void)
  913. {
  914.     int err;
  915.     if (virtual_file == NULL)
  916.     {
  917.         virtual_file = fopen("POV-Ray.imageTemp","wb+");
  918.         err = ferror(virtual_file);
  919.     }
  920.     virtual_currentSegment = -1;
  921.     virtual_bufferDirty = 0;
  922.     virtual_minY = 32767;
  923.     virtual_maxY = 0;
  924.     virtual_pixHeight = virtual_segSize / (global_width * 4);
  925. }
  926.  
  927.  
  928. void delete_virtual(void)
  929. {
  930.     int i;
  931.     if (virtual_file)
  932.     {
  933.         fclose (virtual_file);
  934.         virtual_file = NULL;
  935.     }
  936.     i = remove("POV-Ray.imageTemp");    // Thanks Eduard  (any time, I got the space :-))
  937. }
  938.  
  939. void dispose_virtual(void)
  940. {
  941.     Handle h;
  942.  
  943.     if (plot_pixmap)
  944.     {
  945.         h = RecoverHandle(plot_pixmap);
  946.         HUnlock(h);
  947.         DisposHandle(h);
  948.         plot_pixmap = NULL;
  949.         undoable = 0;
  950.     }
  951.  
  952.     if (undo_buffer)
  953.         DisposePtr(undo_buffer);
  954.     if (undo_buffer2)
  955.         DisposePtr(undo_buffer2);
  956.     if (revert_buffer)
  957.         DisposePtr(revert_buffer);
  958.     undo_buffer = 0;
  959.     undo_buffer2 = 0;
  960.     revert_buffer = 0;
  961.  
  962.     delete_virtual();
  963.     virtual_minY = 32767;
  964. }
  965.  
  966.  
  967. void swap_virtual_segment (short y)
  968. {
  969.     int i;
  970.         
  971.     if ( virtual_file && ((y < virtual_minY) || (y >= virtual_maxY)) )
  972.     {
  973.         if (virtual_bufferDirty && (virtual_currentSegment >= 0))
  974.         {
  975.             fseek(virtual_file, (virtual_currentSegment * virtual_segSize), SEEK_SET);
  976.             if ( fwrite((char *) plot_pixmap, virtual_segSize, 1, virtual_file) != 1)
  977.             {
  978.                 dispose_virtual();
  979.                 return;
  980.             }
  981.         }
  982.  
  983.         virtual_currentSegment = (int) (y / virtual_pixHeight);
  984.         virtual_minY = virtual_currentSegment * virtual_pixHeight;
  985.         virtual_maxY = (virtual_currentSegment + 1) * virtual_pixHeight;
  986.  
  987.         fseek(virtual_file, (virtual_currentSegment * virtual_segSize), SEEK_SET);
  988.         i = fread((char *) plot_pixmap, virtual_segSize, 1, virtual_file);
  989.         virtual_bufferDirty = 0;
  990.  
  991.     }
  992.  
  993. }
  994.  
  995.  
  996. void display_init(int width, int height)
  997. {
  998.     long    *p, *q, pmsize, i;
  999.     Handle    h;
  1000.     Rect    brect;
  1001.     int        insuff_flag;
  1002.  
  1003.  
  1004.     global_width = width;
  1005.     global_height = height;
  1006.     global_bufsize = 4L * (long) width * (long) height;
  1007.     global_y = 0;
  1008.     lastDrawnY = 0;
  1009.     if (plot_window)
  1010.     {
  1011.         DisposeWindow(plot_window);
  1012.         plot_window = NULL;
  1013.     }
  1014.     
  1015.     dispose_virtual(); /* also disposes all old Pixmaps */
  1016.  
  1017.     SetRect(&plot_bounds, 0, 0, width, height);
  1018.     SetRect(&disp_plot_bounds, 0, 0, width * display_magniFactor, height * display_magniFactor);
  1019.     pmsize = 4L * width * height;
  1020.  
  1021.     virtual_bufferDirty = 0;
  1022.  
  1023.     if ((pmsize < ((FreeMem() - virtual_segSize) * 2 / 5)) || (pmsize < virtual_segSize))
  1024.         h = NewHandle(pmsize);
  1025.     else
  1026.             h = 0;
  1027.  
  1028.     if (h)
  1029.     {
  1030.         MoveHHi(h);
  1031.         HLock(h);
  1032.         plot_pixmap = *h;
  1033.         q = (long *) ((long) plot_pixmap + pmsize);
  1034.         for (p = (long *) plot_pixmap; p < q; *p++ = -1);    /* fill to white */
  1035.         (*pm)->bounds = plot_bounds;
  1036.         (*pm)->rowBytes = width * 4 | 0x8000;
  1037.         (*pm)->baseAddr = plot_pixmap;
  1038.         ditherTime = 600;    /* 10 seconds between re-dithers */
  1039.     }
  1040.     else
  1041.     {
  1042.         open_virtual();
  1043.         SetRect(&plot_bounds, 0, 0, width, virtual_pixHeight);
  1044.  
  1045.         if (virtual_file)
  1046.             h = NewHandle(virtual_segSize);
  1047.         ditherTime = 7200;    /* 2 minutes between re-dithers */
  1048.         insuff_flag = 133;
  1049.         if (h)
  1050.         {
  1051.             insuff_flag = 139;
  1052.             MoveHHi(h);
  1053.             HLock(h);
  1054.             plot_pixmap = *h;
  1055.             (*pm)->bounds = plot_bounds;
  1056.             (*pm)->rowBytes = width * 4 | 0x8000;
  1057.             (*pm)->baseAddr = plot_pixmap;
  1058.  
  1059.             q = (long *) ((long) plot_pixmap + virtual_segSize);
  1060.             for (p = (long *) plot_pixmap; p < q; *p++ = -1);    /* fill to white */
  1061.  
  1062.             printf("Creating Virtual Screen Buffer..\n");
  1063.             for (i=0; i < global_height; i++)
  1064.             {
  1065.                 virtual_bufferDirty = 1;
  1066.                 swap_virtual_segment (i);
  1067.             }
  1068.  
  1069.             swap_virtual_segment (0);                        /* swap in segment 0 */
  1070.             if (virtual_file == NULL)
  1071.                 dispose_virtual();
  1072.         }
  1073.         else
  1074.             dispose_virtual;
  1075.  
  1076.         /* if we can't allocate 64K, things are REALLY up the creek */
  1077.         if (virtual_file == NULL)
  1078.             error_dialog(insuff_flag);
  1079.     }
  1080.  
  1081.     if (display_magniFactor)
  1082.     {
  1083.         brect = disp_plot_bounds;
  1084.         OffsetRect(&brect, file_settings->imageWind_pos.left, file_settings->imageWind_pos.top);
  1085.         forceRectOnScreen(&brect);
  1086.         plot_window = NewCWindow(NULL, &brect, theFileName, true, noGrowDocProc,
  1087.                                                         (WindowPtr) -1L, false, 0);
  1088.     }
  1089.     SetCursor(&qd.arrow);    /* it could still be a text cursor from the console */
  1090. }
  1091.  
  1092.  
  1093. void Cooperate(void)
  1094. {
  1095.     if (TICKS > (MyTickCount+MultiFriendly))
  1096.     {
  1097.         MacDawdle();
  1098.         // Don't start the clock again until after all other applications get their shot in.
  1099.         MyTickCount = TICKS;
  1100.     }
  1101. }
  1102.  
  1103. void display_plot (int x, int y, 
  1104.                      unsigned char Red, unsigned char Green, unsigned char Blue)
  1105. {
  1106.     RGBColor c;
  1107.     unsigned char *pptr;
  1108.     Rect myInvalRect, magniRect;
  1109.     long pport_y;
  1110.     int mr_y;
  1111.  
  1112.     global_y = y;
  1113.  
  1114.     if (plot_pixmap)
  1115.     {
  1116.         if (virtual_file)
  1117.         {
  1118.             swap_virtual_segment(y);
  1119.             pport_y = y - virtual_minY;        /* Y offset within current virtual segment */
  1120.             virtual_bufferDirty = TRUE;
  1121.             if (virtual_file == NULL)
  1122.                 error_dialog(141);
  1123.         }
  1124.         else
  1125.             pport_y = y;
  1126.  
  1127.         pptr = (unsigned char *) 
  1128.                 ((long) plot_pixmap + 4L * ((long) plot_bounds.right * pport_y + (long) x));
  1129.         *pptr++ = 0;
  1130.         *pptr++ = Red;
  1131.         *pptr++ = Green;
  1132.         *pptr = Blue;
  1133.     }
  1134.  
  1135.     if (plot_window)
  1136.     {
  1137.         SetPort(plot_window);
  1138.         c.red = (short) Red * 256 ;
  1139.         c.green = ((short) Green) * 256 ;
  1140.         c.blue = ((short) Blue) * 256 ;
  1141.         if (display_magniFactor == 1)
  1142.             SetCPixel(x, y, &c);
  1143.         else
  1144.         {
  1145.             mr_y = (global_y * display_magniFactor);
  1146.             magniRect.top = mr_y;
  1147.             magniRect.bottom = mr_y + display_magniFactor;
  1148.             magniRect.left = x * display_magniFactor;
  1149.             magniRect.right = (x+1) * display_magniFactor;
  1150.             RGBForeColor(&c);
  1151.             PaintRect(&magniRect);
  1152.             ForeColor(blackColor);
  1153.         }
  1154.         if    ((TICKS > (MyRefreshCount + ditherTime)) && (backgrounding == 0))
  1155.         {
  1156.             if (y > (lastDrawnY + 1))
  1157.             {
  1158.                 if (file_settings->ditherPaint)
  1159.                 {
  1160.                     myInvalRect.top = 0;
  1161.                     myInvalRect.bottom = (y + 1) * display_magniFactor;
  1162.                     myInvalRect.left = 0;
  1163.                     myInvalRect.right = global_width * display_magniFactor;
  1164.                 }
  1165.                 else
  1166.                 {
  1167.                     myInvalRect.top =  (lastDrawnY - 1) * display_magniFactor;
  1168.                     myInvalRect.bottom = (y + 1) * display_magniFactor;
  1169.                     myInvalRect.left = 0;
  1170.                     myInvalRect.right = global_width * display_magniFactor;
  1171.                 }
  1172.  
  1173.                 SetPort (plot_window);
  1174.                 InvalRect(&myInvalRect);
  1175.                 MacDawdle();
  1176.  
  1177.                 lastDrawnY = y;
  1178.                 MyRefreshCount = TICKS;
  1179.             }
  1180.         }
  1181.     }
  1182. }
  1183.  
  1184. void paint_whole_window(void)
  1185. {
  1186.     BitMap        bmap;
  1187.     short         myMode, i;
  1188.     Rect        my_bounds;
  1189.  
  1190.     if (plot_window)
  1191.     {
  1192.         if (plot_pixmap)
  1193.         {
  1194.             bmap.baseAddr = (Ptr) pm;
  1195.             bmap.rowBytes = 0xC000;
  1196.             bmap.bounds = plot_bounds;
  1197.             if ((file_settings->ditherPaint) && (qd32_Available))
  1198.                 myMode = ditherCopy;
  1199.             else
  1200.                 myMode = srcCopy;
  1201.  
  1202.             if (virtual_file)
  1203.                 for (i=0; i < global_height; i = i + virtual_pixHeight)
  1204.                 {
  1205.                     swap_virtual_segment (i);
  1206.                     my_bounds.top = (i * display_magniFactor);
  1207.                     my_bounds.bottom = my_bounds.top + (virtual_pixHeight * display_magniFactor);
  1208.                     /* don't worry about the bounds, the clipping region of the window will stop
  1209.                         us from drawing past the bottom */                    
  1210.                     my_bounds.left = 0;
  1211.                     my_bounds.right = global_width * display_magniFactor;
  1212.                     CopyBits(&bmap, &plot_window->portBits, &plot_bounds, &my_bounds,
  1213.                              myMode, NULL);
  1214.                 }
  1215.             else
  1216.                     CopyBits(&bmap, &plot_window->portBits, &plot_bounds, &disp_plot_bounds,
  1217.                              myMode, NULL);
  1218.         }
  1219.      }
  1220. }
  1221.  
  1222. pascal void MyPutPicProc( char *dataPtr, short byteCount)
  1223. {
  1224.     int myByteCount;
  1225.  
  1226.     myByteCount = byteCount;
  1227.     myPicSize += byteCount;
  1228.     if (savePICT_file)
  1229.     {
  1230.         if (fwrite( dataPtr, 1, myByteCount, savePICT_file) != myByteCount)
  1231.         {
  1232.             fclose (savePICT_file);
  1233.             savePICT_file = 0;
  1234.         }
  1235.     }
  1236.     // we have to keep the picture handle header updated for Quickdraw!
  1237.     if (myPicHandle)
  1238.         (**myPicHandle).picSize = myPicSize;
  1239. }
  1240.  
  1241.  
  1242. void paint_to_picture(short do_disk_buffer)
  1243. {
  1244.     BitMap        bmap;
  1245.     short         myMode, i;
  1246.     OSErr        anError;
  1247.     Rect        my_bounds, myPicRect;    
  1248.     CGrafPort    myCGrafPtr;
  1249.     GrafPtr        oldGrafPtr;
  1250.     PictFHeader    myPictFHeader;
  1251.     CQDProcs    myQDProcs;
  1252.  
  1253.     anError = noErr;
  1254.     if (plot_pixmap)
  1255.     {
  1256.         GetPort(&oldGrafPtr);
  1257.         OpenCPort (&myCGrafPtr);
  1258.         SetPort ((GrafPtr)&myCGrafPtr);
  1259.  
  1260.         PortSize (global_width, global_height);
  1261.         myPicRect.top = 0;
  1262.         myPicRect.bottom = global_height;
  1263.         myPicRect.left = 0;
  1264.         myPicRect.right = global_width;
  1265.  
  1266.         ClipRect(&myPicRect);
  1267.  
  1268.         if (do_disk_buffer)
  1269.         {
  1270.             SetStdCProcs ((CQDProcsPtr) &myQDProcs);
  1271.             myQDProcs.putPicProc = (Ptr) MyPutPicProc;
  1272.             myCGrafPtr.grafProcs = (CQDProcsPtr) &myQDProcs;
  1273.             // write the PICT header to the file
  1274.             myPicSize = sizeof(myPictFHeader);
  1275.             myPictFHeader.picSize = myPicSize; // accumulated later in MyPutPicProc()..
  1276.             myPictFHeader.picFrame = myPicRect;
  1277.             i = fwrite (&myPictFHeader, 1, sizeof(myPictFHeader), savePICT_file);
  1278.             anError = ferror(savePICT_file);
  1279.         }
  1280.  
  1281.         if (!anError)
  1282.         {
  1283.             /* insure myPicHandle null, 'cause MyPutPicProc will be called in OpenPicture! */
  1284.             myPicHandle = NULL;
  1285.             myPicHandle = OpenPicture (&myPicRect);
  1286.             anError = QDError();
  1287.         }
  1288.  
  1289.         bmap.baseAddr = (Ptr) pm;
  1290.         bmap.rowBytes = 0xC000;    // flag for PixMap
  1291.         if ((file_settings->ditherPaint) && (qd32_Available))
  1292.             myMode = ditherCopy;
  1293.         else
  1294.             myMode = srcCopy;
  1295.  
  1296.         if (!anError)
  1297.         {
  1298.             if (virtual_file)
  1299.                 for (i=0; (i <= global_height) && !anError; i = i + virtual_pixHeight)
  1300.                 {
  1301.                     swap_virtual_segment (i);
  1302.                     my_bounds.top = i;
  1303. // NOTE, JIM! (next source line)
  1304. // By doing a CopyBits of the last rect in full, the whole rect of pixels _does_
  1305. // get written to the PICT file, even though not all the scan lines are valid..
  1306. // this doesn't hurt anything, just makes the file a little bigger than it needs to be,
  1307. // since the extra lines will get clipped on playback.  However, since plot_bounds is
  1308. // global, it would be icky to temporarily change its bottom along with my_bounds so
  1309. // as to only write the necessary lines.. maybe later. :-)
  1310.                     my_bounds.bottom = i + virtual_pixHeight;
  1311.                     my_bounds.left = 0;
  1312.                     my_bounds.right = global_width;
  1313.                     CopyBits(&bmap, (BitMap *)&myCGrafPtr.portPixMap, &plot_bounds, &my_bounds,
  1314.                              myMode, NULL);
  1315.                     anError = QDError();
  1316.                 }
  1317.             else
  1318.                 {
  1319.                 CopyBits(&bmap, (BitMap *)&myCGrafPtr.portPixMap, &plot_bounds, &plot_bounds,
  1320.                          myMode, NULL);
  1321.                 anError = QDError();
  1322.                 }
  1323.         }
  1324.  
  1325.         /* write end-of-picture */
  1326.         if (!anError)
  1327.         {
  1328.             ClosePicture();
  1329.             anError = QDError();
  1330.         }
  1331.  
  1332.         if (!anError)
  1333.         {
  1334.             if (do_disk_buffer)
  1335.             {
  1336.                 /* don't call us anymore! */
  1337.                 SetStdCProcs((CQDProcsPtr) &myQDProcs);
  1338.  
  1339.                 /* move back to pic header again */
  1340.                 fflush(savePICT_file);
  1341.                 fseek(savePICT_file, PICTF_HEADER_SIZE, SEEK_SET);
  1342.                 anError = ferror(savePICT_file);
  1343.                 /* update the PICT header in the file (with now-true picSize field..) */
  1344.                 if (!anError)
  1345.                 {
  1346.                     myPictFHeader.picSize = myPicSize;
  1347.                     i = fwrite (&myPictFHeader, 1, sizeof(myPictFHeader), savePICT_file);
  1348.                     anError = ferror(savePICT_file);
  1349.                 }
  1350.             }
  1351.             else
  1352.             {
  1353.                 ZeroScrap();
  1354.                 HLock((Handle) myPicHandle);
  1355.                 myPicSize = GetHandleSize((Handle) myPicHandle);
  1356.                 PutScrap (myPicSize, 'PICT', (Ptr) *myPicHandle);
  1357.                 myPicSize = UnloadScrap();
  1358.                 HUnlock((Handle) myPicHandle);
  1359.             }
  1360.         } // if !error
  1361.  
  1362.         /* close up shop */
  1363.         CloseCPort(&myCGrafPtr);
  1364.         SetPort(oldGrafPtr);
  1365.         if (myPicHandle)
  1366.             DisposeHandle((Handle) myPicHandle);
  1367.  
  1368.         /* oh yeah, check for errors */
  1369.         if (anError)
  1370.         {
  1371.             if (savePICT_file)
  1372.             {
  1373.                 fclose (savePICT_file);
  1374.                 savePICT_file = 0;
  1375.             }
  1376.             SysBeep(4);
  1377.         }
  1378.  
  1379.     } // if plot_pixmap..
  1380. } // paint_to_picture()
  1381.  
  1382.  
  1383. /* Write the Pixmap as a PICT file */
  1384. void saveOutputFile(int getName)
  1385. {
  1386.     SFReply        reply;
  1387.     Point         where;
  1388.     char        cFname[256];
  1389.     char        filler[PICTF_HEADER_SIZE];
  1390.     int         i;
  1391.     FInfo        myFileInfo;
  1392.     FSSpec        fsFile;        
  1393.     Rect        myPicRect;    
  1394.  
  1395.     for (i=0; i<PICTF_HEADER_SIZE; i++)
  1396.         filler[i] = 0;
  1397.     strcpy (cFname, c_theFileName);
  1398.     if    (strstr(cFname,".POV") || strstr(cFname,".pov"))
  1399.     {
  1400.         i = strlen(cFname);
  1401.         cFname[i - 4] = 0;
  1402.     }
  1403.     strcat (cFname, ".PICT");
  1404.  
  1405.     if (getName)
  1406.     {
  1407.         CtoPstr(cFname);
  1408.         where.h = where.v = 82;
  1409.         SFPutFile (where, "\pSave PICT file as╔", cFname, NULL, &reply);
  1410.     }
  1411.     else
  1412.     {
  1413.         strcpy ((char *) reply.fName,cFname);
  1414.         CtoPstr(reply.fName);
  1415.         reply.vRefNum = theVRefNum;
  1416.         reply.good = TRUE;
  1417.     }
  1418.     if (reply.good)
  1419.     {
  1420.         PtoCstr(reply.fName);
  1421.         SetVol(NULL, reply.vRefNum);
  1422.         savePICT_file = fopen((char *) reply.fName,"wb");
  1423.         if (savePICT_file)
  1424.         {        
  1425.  
  1426.             i = fwrite (&filler, 1, PICTF_HEADER_SIZE, savePICT_file);
  1427.             
  1428.             paint_to_picture(TRUE);
  1429.  
  1430.             if (savePICT_file)
  1431.                 {
  1432.                     fclose (savePICT_file);
  1433.                     savePICT_file = 0;
  1434.                     CtoPstr(reply.fName);
  1435.  
  1436. // real hokey temporary hack to only allow compression if option key down.
  1437. // NOTE: I did it this way, because we will use the doPictCompression flag later
  1438. // when we read the compression checkbox option from the file/app prefs dialog.
  1439.                     /* TEMPORARY way to see if user wants compression */
  1440.                     if (myEvent.modifiers & optionKey)
  1441.                         doPictCompression = true;
  1442.                     else
  1443.                         doPictCompression = false;
  1444.  
  1445.                     /* If QuickTime is around & user wants to squish the picture, ask user how to squish it */
  1446.                     if (ImageCompressionMgrAvailable && doPictCompression)
  1447.                     {
  1448.                         myPicRect.top = 0;
  1449.                         myPicRect.bottom = global_height;
  1450.                         myPicRect.left = 0;
  1451.                         myPicRect.right = global_width;
  1452.                         i = FSMakeFSSpec(reply.vRefNum, 0, reply.fName, &fsFile);
  1453.                         if (!i)
  1454.                             if (PromptForCompressionStyle(gtheSCComponent, &gSCDialogParams, &fsFile))
  1455.                                 i=CompressPictF(&gSCDialogParams, &fsFile);
  1456. // not yet tested and working, but leave in for later..
  1457. //                        /* stick a preview resource on it too */
  1458. //                        if (!i)
  1459. //                            i = AppendFilePreview2PictF(&fsFile);
  1460.  
  1461. // not yet tested and working, but leave in for later..
  1462. //                        /* Add System 7 custom icons of the image itself to the file */
  1463. //                        if (!i)
  1464. //                            i = AppendFinderIcons2PictF(&fsFile, &myPicRect, eAFI_ShrinkWholeImage);
  1465.                     }
  1466.                     i = GetFInfo (reply.fName, reply.vRefNum, &myFileInfo);
  1467.                     if (i==0)
  1468.                     {
  1469.                         myFileInfo.fdType = 'PICT';
  1470.                         myFileInfo.fdCreator = 'ttxt';
  1471.                         i = SetFInfo (reply.fName, reply.vRefNum, &myFileInfo);
  1472.                     }
  1473.                 }
  1474.             else
  1475.                 error_dialog(140);
  1476.         }
  1477.     }
  1478. }    
  1479.  
  1480.  
  1481. /* --- And now for the real Mac stuff --- */
  1482.  
  1483. char *PrintTime()
  1484. {
  1485.     static Str255    t;
  1486.     unsigned long    secs;
  1487.     
  1488.     GetDateTime(&secs);
  1489.     IUTimeString(secs, true, t);
  1490.     return (char *) t;
  1491. }
  1492.  
  1493. void call_main(int argc, char *argv[])
  1494. {
  1495.  
  1496.     if (setjmp(env) == 0)
  1497.     {
  1498.         POV_running = 1;
  1499.         /* deallocate any previous windows */
  1500.         if (plot_window)
  1501.         {
  1502.             DisposeWindow(plot_window);
  1503.             plot_window = NULL;
  1504.         }
  1505.     
  1506.         dispose_virtual(); /* also disposes all old Pixmaps */
  1507.  
  1508.         MyTickCount = TICKS;
  1509.         rendered_OK = 1;    /* presume that rendering will finish OK */
  1510.         printf("\n");
  1511.         Collect_Garbage();    
  1512.         Max_Trace_Level = 5.0;
  1513.         token_count = 0;
  1514.         line_count = 0;
  1515.         Construction_Map = NULL;
  1516.         Targa_Line_Number = 0;
  1517.         alt_main(argc, argv);
  1518.  
  1519.         if (rendered_OK)
  1520.             ChangeTargaType();    /* change type and creator of the Targa output file */
  1521.         if (plot_window)
  1522.         {
  1523.             SetPort (plot_window);
  1524.             InvalRect (&disp_plot_bounds);
  1525.         }
  1526.     }
  1527.  
  1528.     POV_running = 0;
  1529.     run_flag = 0;
  1530. }
  1531.  
  1532.  
  1533. void AddArg(const char *s)
  1534. {
  1535.     ARGV[ARGC++] = argptr;
  1536.     while (*argptr++ = *s++);
  1537. }
  1538.  
  1539.  
  1540. void PinValue(short *x, short a, short b)
  1541. {
  1542.     if (*x < a)
  1543.         *x = a;
  1544.     else
  1545.         if (*x > b)
  1546.             *x = b;
  1547. }
  1548.  
  1549.  
  1550. OSErr OpenPrefsFile(void)
  1551. {
  1552.     long    theResponse;        /* For call to Gestalt */
  1553.     OSErr    errCode;
  1554.     long    prefs_dirID;
  1555.     short    prefs_volNum;
  1556.  
  1557.     /* default in case neither FindFolder nor SysEnvirons can help locate the Preference Folder */
  1558.     prefs_dirID = 0;
  1559.     prefs_volNum = 0;
  1560.     
  1561.     errCode = -1;
  1562.     if (Gestalt_Available)
  1563.     {
  1564.         /* Find the preferences folder */
  1565.         errCode = Gestalt(gestaltFindFolderAttr, &theResponse);
  1566.         
  1567.         if (errCode == noErr && (BitTst((Ptr)&theResponse, 31 - gestaltFindFolderPresent)))
  1568.           errCode = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  1569.                &prefs_volNum, &prefs_dirID);
  1570.     }
  1571.     if (errCode)
  1572.     {
  1573.          SysEnvRec    theWorld;
  1574.  
  1575.         /* Error locating the preferences folder, so use the blessed folder */
  1576.         if ((errCode = SysEnvirons(1, &theWorld)) == noErr)
  1577.             prefs_volNum = theWorld.sysVRefNum;
  1578.         else
  1579.             /* Had a problem with SysEnvirons, try the default volume */
  1580.             prefs_volNum = 0;
  1581.         prefs_dirID = 0;
  1582.     }
  1583.  
  1584.     /* Create the prefs file.  If it's already created, no need to create the resource fork. */
  1585.     if ((errCode = HCreate(prefs_volNum, prefs_dirID, "\pPOV-Ray Prefs",
  1586.      kAppSignature, 'SETT')) == noErr)
  1587.     {
  1588.         HCreateResFile(prefs_volNum, prefs_dirID, "\pPOV-Ray Prefs");
  1589.         errCode = ResError();
  1590.     }
  1591.  
  1592.     /* Return an error code */
  1593.     if (errCode == dupFNErr) /* file's already created?  Not an error. */
  1594.         errCode = noErr;
  1595.     if (errCode == noErr)
  1596.     {
  1597.         prefsRefNum = HOpenResFile(prefs_volNum, prefs_dirID, "\pPOV-Ray Prefs",
  1598.             fsRdWrPerm);
  1599.            if (prefsRefNum == -1)
  1600.                errCode = -1;
  1601.            if (ResError())
  1602.                errCode = ResError();
  1603.        }
  1604.     return errCode;
  1605. }
  1606.  
  1607. void Write_Our_Prefs(void)
  1608. {
  1609.         ChangedResource((Handle) global_settings_h);
  1610.         WriteResource((Handle) global_settings_h);
  1611.         if (ResError())
  1612.         {
  1613.             error_dialog(144);
  1614.             global_settings_h = 0;
  1615.             exit_handler();
  1616.         }
  1617.         UpdateResFile(prefsRefNum);
  1618. }
  1619.  
  1620.  
  1621. void goto_line(short line_to_go)
  1622. {
  1623.     short        i;
  1624.     short        line_counter = 1,
  1625.                 mySelStart = -1,
  1626.                 mySelEnd = -1;
  1627.     Boolean        foundStart = false;
  1628.     short        theMaxLength = (**TEH).teLength-1;
  1629.     char        *myptr = *(**TEH).hText;
  1630.  
  1631.     /* (Line 1 is a special case, of course!) */
  1632.     if (line_to_go <= 1)
  1633.     {
  1634.         mySelStart = 0;
  1635.         foundStart = true;
  1636.     }
  1637.  
  1638.     /* Find start and end of line */
  1639.     for (i = 0; i < theMaxLength; i++)
  1640.         if (myptr[i] == 0x0d)
  1641.             if (!foundStart)
  1642.             {    /* still looking for start of the line */
  1643.                 line_counter += 1;
  1644.                 if (line_counter == line_to_go)
  1645.                 {
  1646.                     mySelStart = i + 1;
  1647.                     foundStart = true;
  1648.                 }
  1649.             }
  1650.             else
  1651.             {    /* now we found the end of the line */
  1652.                 mySelEnd = i + 1;
  1653.                 break;
  1654.             }
  1655.  
  1656.     /* Beep if we found no start of line */
  1657.     if ((mySelStart < 0) && (line_to_go > 1))
  1658.     {    /* Hmm, didn't find it! */
  1659.         mySelStart = 0;
  1660.         mySelEnd = 0;
  1661.         SysBeep(4);
  1662.     }
  1663.  
  1664.     /* if no end of line found, ASSUME it is last line of file  */
  1665.     if (mySelEnd < mySelStart)
  1666.         mySelEnd = theMaxLength;
  1667.  
  1668.     /* Set up TE with selection */
  1669.     (**TEH).selStart = mySelStart;
  1670.     (**TEH).selEnd = mySelEnd;
  1671.  
  1672.     /* show them that we're not in Kansas anymore! */
  1673.     ShowSelect();
  1674. }
  1675.  
  1676.  
  1677. #define    kItem_LineNum    4
  1678.  
  1679. void choose_goto_line(void)
  1680. {
  1681.     short        i, dummyInt, remember_Opts, line_to_go;
  1682.     Rect        displayRect;
  1683.     ControlHandle cntl[31];
  1684.     char        s1[256];
  1685.     HiliteMenu(0);
  1686.     DisableItem(myMenus[1], 1); /* about box */
  1687.     DisableItem(myMenus[fmn_ID], 0); /* File menu */
  1688.     DisableItem(myMenus[edmn_ID], edmn_undo); /* Undo */
  1689.     
  1690.     do_notify = 0;            /* in case dialog was selected before some notification completed */
  1691.     line_to_go = 1; /* for now */
  1692.     UseResFile(ourRefNum);
  1693.     myDialog = GetNewDialog(150, NULL, (WindowPtr) -1);
  1694.     remember_Opts = 0;
  1695.     for (i = 1; i <= 4; i++)
  1696.         GetDItem(myDialog, i, &dummyInt, (Handle *) &cntl[i], &displayRect);
  1697.     sprintf(s1, "%d", line_to_go); 
  1698.     SetIText((Handle) cntl[kItem_LineNum], CtoPstr(s1) );
  1699.     SelIText(myDialog, kItem_LineNum, 0, 32767);
  1700.     /* "default" the OK button */
  1701.     SetupDefaultButton(myDialog);
  1702.     do
  1703.     {
  1704.         ModalDialog((ModalFilterProcPtr)ModalFilter, &itemHit);
  1705.     }
  1706.     while (itemHit != OK && itemHit != Cancel);
  1707.     
  1708.     if (itemHit == OK)
  1709.     {
  1710.         GetIText((Handle) cntl[kItem_LineNum], s1); sscanf(PtoCstr(s1) , "%hd", &line_to_go);
  1711.         PinValue(&line_to_go, 0, 32767);
  1712.     }
  1713.     DisposDialog(myDialog); myDialog = NULL;
  1714.     if (itemHit == OK)
  1715.         goto_line(line_to_go);
  1716.     EnableItem(myMenus[1], 1); /* about box */
  1717.     EnableItem(myMenus[fmn_ID], 0); /* File menu */    
  1718.     EnableItem(myMenus[edmn_ID], edmn_undo); /* undo */
  1719.     DrawMenuBar();
  1720. }
  1721.  
  1722. void GetPreferences(void)
  1723. {
  1724.     DialogPtr    updatingDialog;
  1725.     if (OpenPrefsFile() != noErr)
  1726.     {
  1727.         error_dialog(145);
  1728.         exit_handler();
  1729.     }
  1730.  
  1731.     /* Get saved settings for Render Options dialog from the Prefs file */
  1732.     theUpdateRgn = NewRgn();
  1733.     UseResFile(prefsRefNum);
  1734.     global_settings_h = (prefs_hdl_t) Get1Resource('DFLT', kSettings_rsrcID);
  1735.     if (global_settings_h != NULL)
  1736.     {
  1737.         /* Is it the wrong version? */
  1738.         if ((**global_settings_h).prefs_version != kSettings_vers)
  1739.         {    /* old version, delete & create new one below! */
  1740.             RmveResource((Handle)global_settings_h);
  1741.             global_settings_h = NULL; /* flag code below to add new */
  1742.         }
  1743.         /* Still got it?  Use it! */
  1744.         if (global_settings_h != NULL)
  1745.         {
  1746.             MoveHHi((Handle) global_settings_h);
  1747.             HLock((Handle) global_settings_h);
  1748.             global_settings = *global_settings_h;
  1749.             /* make sure our windows are visible on THIS MACHINE'S screens */
  1750.             forceRectOnScreen(&global_settings->srcWind_pos);
  1751.             forceRectOnScreen(&global_settings->statWind_pos);
  1752.             forceRectOnScreen(&global_settings->imageWind_pos);
  1753.         }
  1754.     }
  1755.     /* create a new one if can't read or use the old one */
  1756.     if (global_settings_h == NULL)
  1757.     {
  1758.         TargetTicks = TICKS + 180L;
  1759.         updatingDialog = GetNewDialog (147, NULL, (WindowPtr) -1);
  1760.         if (updatingDialog)
  1761.             DrawDialog(updatingDialog);
  1762.         global_settings_h = (prefs_hdl_t) NewHandle(sizeof(prefs_rec_t));
  1763.         if (global_settings_h == 0)
  1764.         {
  1765.             error_dialog(132);
  1766.             exit_handler();
  1767.         }
  1768.         MoveHHi((Handle) global_settings_h);
  1769.         HLock((Handle) global_settings_h);
  1770.         global_settings = *global_settings_h;
  1771.         global_settings->prefs_version = kSettings_vers;
  1772.         SetRect(&global_settings->srcWind_pos,
  1773.                         8,
  1774.                         GetMBarHeight()+20,
  1775.                         min(600, qd.screenBits.bounds.right-40),
  1776.                         qd.screenBits.bounds.bottom-40);
  1777.         SetRect(&global_settings->statWind_pos,
  1778.                         20, GetMBarHeight()+40,
  1779.                         480, 240);
  1780.         SetRect(&global_settings->imageWind_pos,
  1781.                         8, GetMBarHeight()+20,
  1782.                         8, GetMBarHeight()+20);
  1783.         global_settings->width = 320;
  1784.         global_settings->height = 240;
  1785.         global_settings->from = 0;
  1786.         global_settings->to = 240;
  1787.         global_settings->threshold = 0.30;
  1788.         global_settings->quality = 9;
  1789.         global_settings->howMultiFriendly = kDefMultiFriendly;
  1790.         global_settings->cr_file = false;
  1791.         global_settings->resume = false;
  1792.         global_settings->antialias = false;
  1793.         global_settings->ditherPaint = true;
  1794.         global_settings->magniFactor = 1;
  1795.         global_settings->request_shutdown = false;
  1796.         strcpy(global_settings->paths,":::Include:\x0d::Include:\x0d");
  1797.  
  1798.         UseResFile(prefsRefNum);
  1799.         AddResource ((Handle) global_settings_h, 'DFLT', kSettings_rsrcID, "\pRender Options");
  1800.         Write_Our_Prefs();
  1801.         if (updatingDialog)
  1802.         {
  1803.             while (TICKS < TargetTicks)
  1804.                 { };
  1805.             DisposeDialog(updatingDialog);
  1806.             updatingDialog = 0;
  1807.         }
  1808.     }    
  1809. }
  1810.  
  1811.  
  1812. void GetFileSettings(void)
  1813. {
  1814.     Handle tmpHandle;
  1815.  
  1816.     SetVol(NULL, theVRefNum);
  1817.     fileResRefNum = OpenResFile(theFileName);
  1818.     if (fileResRefNum == -1)
  1819.     {
  1820.         CreateResFile(theFileName);
  1821.         fileResRefNum = OpenResFile(theFileName);
  1822.         if (fileResRefNum == -1)
  1823.             return;
  1824.     }
  1825.     tmpHandle = Get1Resource ('SETT', kSettings_rsrcID);
  1826.     if (tmpHandle != NULL)
  1827.     {
  1828.         /* delete old file_settings_h first! */
  1829.         if (file_settings_h)
  1830.         {
  1831.             DisposeHandle((Handle)file_settings_h);
  1832.             file_settings_h = NULL;
  1833.         }
  1834.         /* Is it the wrong version? */
  1835.         if ((**(prefs_hdl_t)tmpHandle).prefs_version != kSettings_vers)
  1836.         {    /* old version, delete & create new one below! */
  1837.             RmveResource(tmpHandle);
  1838.             tmpHandle = NULL; /* flag code below to add new */
  1839.         }
  1840.         /* Still got it?  Use it! */
  1841.         if (tmpHandle != NULL)
  1842.         {
  1843.             file_settings_h = (prefs_hdl_t) tmpHandle;
  1844.             MoveHHi((Handle) file_settings_h);
  1845.             HLock((Handle) file_settings_h);
  1846.             file_settings = *file_settings_h;     /* dereference handle */
  1847.             /* make sure our windows are on THIS MACHINE'S screens */
  1848.             forceRectOnScreen(&file_settings->srcWind_pos);
  1849.             forceRectOnScreen(&file_settings->statWind_pos);
  1850.             forceRectOnScreen(&file_settings->imageWind_pos);
  1851.         }
  1852.     }
  1853.     /* create a new one if can't read or use the old one */
  1854.     if (tmpHandle == NULL)
  1855.     {
  1856.         file_settings_h = (prefs_hdl_t) NewHandle(sizeof(prefs_rec_t));
  1857.         MoveHHi((Handle) file_settings_h);
  1858.         HLock((Handle) file_settings_h);
  1859.         file_settings = *file_settings_h;
  1860.         memcpy (file_settings, global_settings, sizeof(prefs_rec_t));
  1861.         
  1862.         AddResource( (Handle) file_settings_h, 'SETT', kSettings_rsrcID,"\pPOV-Ray Settings");
  1863.         UpdateResFile(fileResRefNum);
  1864.     }
  1865. }
  1866.  
  1867.  
  1868. void WriteFileSettings(void)
  1869. {
  1870.     if (fileResRefNum != -1)
  1871.     {
  1872.         UseResFile(fileResRefNum);
  1873.         ChangedResource( (Handle) file_settings_h);
  1874.         WriteResource( (Handle) file_settings_h);
  1875.         UpdateResFile(fileResRefNum);
  1876.         UseResFile(ourRefNum);
  1877.     }
  1878. }
  1879.  
  1880. void CloseFileSettings(void)
  1881. {
  1882.     if (fileResRefNum != -1)
  1883.         CloseResFile(fileResRefNum);
  1884.     fileResRefNum = -1;
  1885. }
  1886.  
  1887.  
  1888. #define    kItem_gImageWidth            4
  1889. #define    kItem_gImageHeight            5
  1890. #define    kItem_gImageQuality            6
  1891. #define    kItem_gAntiAliasCheck        7
  1892. #define    kItem_gAntiAliasThreshold    8
  1893. #define    kItem_gBgFriendlyCheck        9
  1894. #define    kItem_gSearchPaths            11
  1895.  
  1896. void ChangeGlobalSettings(void)
  1897. {
  1898.     short        i, dummyInt, remember_Opts;
  1899.     Rect        displayRect;
  1900.     ControlHandle cntl[31];
  1901.     char        s1[256];
  1902.  
  1903.     HiliteMenu(0);
  1904.     DisableItem(myMenus[1], 1); /* about box */
  1905.     DisableItem(myMenus[fmn_ID], 0); /* File menu */
  1906.     DisableItem(myMenus[edmn_ID], edmn_undo); /* Undo */
  1907.     
  1908.     do_notify = 0;            /* in case "Open" was selected before notification completed */
  1909.  
  1910.     UseResFile(ourRefNum);
  1911.     myDialog = GetNewDialog(146, NULL, (WindowPtr) -1);
  1912.     remember_Opts = 0;
  1913.     for (i = 1; i <= 12; i++)
  1914.         GetDItem(myDialog, i, &dummyInt, (Handle *) &cntl[i], &displayRect);
  1915.     sprintf(s1, "%d", global_settings->width); 
  1916.     SetIText((Handle) cntl[kItem_gImageWidth], CtoPstr(s1) );
  1917.     sprintf(s1, "%d", global_settings->height); 
  1918.     SetIText((Handle) cntl[kItem_gImageHeight], CtoPstr(s1) );
  1919.     sprintf(s1, "%d", global_settings->quality); 
  1920.     SetIText((Handle) cntl[kItem_gImageQuality], CtoPstr(s1) );
  1921.     SetCtlValue(cntl[kItem_gAntiAliasCheck], global_settings->antialias);
  1922.     sprintf(s1, "%.2f", global_settings->threshold);
  1923.     SetIText((Handle) cntl[kItem_gAntiAliasThreshold], CtoPstr(s1) );
  1924.     SetIText((Handle) cntl[kItem_gSearchPaths], CtoPstr(global_settings->paths) ); PtoCstr(global_settings->paths);
  1925.     sprintf(s1, "%d", global_settings->howMultiFriendly); 
  1926.     SetIText((Handle) cntl[kItem_gBgFriendlyCheck], CtoPstr(s1) );
  1927.     SelIText(myDialog, kItem_gImageWidth, 0, 32767);
  1928.  
  1929.     /* "default" the OK button */
  1930.     SetupDefaultButton(myDialog);
  1931.     do
  1932.     {
  1933.         ModalDialog((ModalFilterProcPtr)ModalFilter, &itemHit);
  1934.         if (itemHit == kItem_gAntiAliasCheck)    
  1935.             SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  1936.         enable_return_key = (itemHit != kItem_gSearchPaths);
  1937.     }
  1938.     while (itemHit != OK && itemHit != Cancel);
  1939.     
  1940.     if (itemHit == OK)
  1941.     {
  1942.         GetIText((Handle) cntl[kItem_gImageWidth], s1); sscanf(PtoCstr(s1) , "%hd", &global_settings->width);
  1943.         PinValue(&global_settings->width, 0, 4095);
  1944.         GetIText((Handle) cntl[kItem_gImageHeight], s1); sscanf(PtoCstr(s1) , "%hd", &global_settings->height);
  1945.         PinValue(&global_settings->height, 0, 4095);
  1946.         global_settings->from = 0;
  1947.         global_settings->to = global_settings->height;
  1948.         GetIText((Handle) cntl[kItem_gImageQuality], s1); sscanf(PtoCstr(s1) , "%hd", &global_settings->quality);
  1949.         global_settings->antialias = GetCtlValue(cntl[kItem_gAntiAliasCheck]);
  1950.  
  1951.         GetIText((Handle) cntl[kItem_gBgFriendlyCheck], s1);                        
  1952.         sscanf(PtoCstr(s1) , "%hd", &global_settings->howMultiFriendly);            
  1953.         PinValue(&global_settings->howMultiFriendly, kMinMultiFriendly, kMaxMultiFriendly);
  1954.         MultiFriendly = global_settings->howMultiFriendly;
  1955.  
  1956.         GetIText((Handle) cntl[kItem_gAntiAliasThreshold], s1); sscanf(PtoCstr(s1) , "%lf", &global_settings->threshold);
  1957.         GetIText((Handle) cntl[kItem_gSearchPaths], global_settings->paths);
  1958.         PtoCstr (global_settings->paths);
  1959.         i = strlen(global_settings->paths);
  1960.         if (global_settings->paths[i - 1] != 13)
  1961.         {
  1962.             global_settings->paths[i] = 13;
  1963.             global_settings->paths[i + 1] = 0;
  1964.         }
  1965.  
  1966.         Write_Our_Prefs();
  1967.     }
  1968.     DisposDialog(myDialog); myDialog = NULL;
  1969.     EnableItem(myMenus[1], 1); /* about box */
  1970.     EnableItem(myMenus[fmn_ID], 0); /* File menu */    
  1971.     EnableItem(myMenus[edmn_ID], edmn_undo); /* undo */
  1972.     DrawMenuBar();
  1973. }
  1974.  
  1975.  
  1976. #define    kItem_fFilename                4
  1977. #define    kItem_fImageWidth            5
  1978. #define    kItem_fImageHeight            6
  1979. #define    kItem_fRowFrom                7
  1980. #define    kItem_fRowTo                8
  1981. #define    kItem_fImageQuality            9
  1982. #define    kItem_fAntiAliasCheck        10
  1983. #define    kItem_fAntiAliasThreshold    11
  1984. #define    kItem_fDoTargaCheck            12
  1985. #define    kItem_fContinueTargaCheck    13
  1986. #define    kItem_fBtnThumbnail            14
  1987. #define    kItem_fBtnPreview            15
  1988. #define    kItem_fBtnFullSize            16
  1989.  
  1990. void ChangeFileSettings(void)
  1991. {
  1992.     DialogPtr    myWarningDialog;
  1993.     short        i, dummyInt, remember_Opts;
  1994.     Rect        displayRect;
  1995.     ControlHandle cntl[31];
  1996.     char        s1[256];
  1997.     char        pFname[256];
  1998.  
  1999.     HiliteMenu(0);
  2000.     DisableItem(myMenus[1], 1); /* about box */
  2001.     DisableItem(myMenus[fmn_ID], 0); /* File menu */
  2002.     DisableItem(myMenus[edmn_ID], edmn_undo); /* Undo */
  2003.     
  2004.     do_notify = 0;            /* in case "Open" was selected before notification completed */
  2005.  
  2006.     strcpy (pFname, c_theFileName);
  2007.     CtoPstr (pFname);
  2008.     UseResFile(ourRefNum);
  2009.     myDialog = GetNewDialog(128, NULL, (WindowPtr) -1);
  2010.     remember_Opts = 0;
  2011.     for (i = 1; i <= 23; i++)
  2012.         GetDItem(myDialog, i, &dummyInt, (Handle *) &cntl[i], &displayRect);
  2013.     SetIText((Handle) cntl[kItem_fFilename], pFname );
  2014.     sprintf(s1, "%d", file_settings->width); SetIText((Handle) cntl[kItem_fImageWidth], CtoPstr(s1) );
  2015.     sprintf(s1, "%d", file_settings->height); SetIText((Handle) cntl[kItem_fImageHeight], CtoPstr(s1) );
  2016.     sprintf(s1, "%d", file_settings->from); SetIText((Handle) cntl[kItem_fRowFrom], CtoPstr(s1) );
  2017.     sprintf(s1, "%d", file_settings->to); SetIText((Handle) cntl[kItem_fRowTo], CtoPstr(s1) );
  2018.     sprintf(s1, "%d", file_settings->quality); SetIText((Handle) cntl[kItem_fImageQuality], CtoPstr(s1) );
  2019.     SetCtlValue(cntl[kItem_fAntiAliasCheck], file_settings->antialias);
  2020.     sprintf(s1, "%.2f", file_settings->threshold); SetIText((Handle) cntl[kItem_fAntiAliasThreshold], CtoPstr(s1) );
  2021.     SetCtlValue(cntl[kItem_fDoTargaCheck], file_settings->cr_file);
  2022.     SetCtlValue(cntl[kItem_fContinueTargaCheck], file_settings->resume);
  2023.     SelIText(myDialog, kItem_fImageWidth, 0, 32767);
  2024.  
  2025.     /* "default" the OK button */
  2026.     SetupDefaultButton(myDialog);
  2027.     do
  2028.     {
  2029.         ModalDialog((ModalFilterProcPtr)ModalFilter, &itemHit);
  2030.         switch (itemHit)
  2031.         {
  2032.             case kItem_fAntiAliasCheck:        /* anti-alias */
  2033.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2034.                 break;
  2035.             case kItem_fDoTargaCheck:  /* Create Targa file */
  2036.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2037.                 if (GetCtlValue(cntl[itemHit]) == 0)
  2038.                     SetCtlValue(cntl[kItem_fContinueTargaCheck],0);    /* no Targa, no Resume. */
  2039.                 break;
  2040.             case kItem_fContinueTargaCheck:            /* Resume interrupted scan */
  2041.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2042.                 if (GetCtlValue(cntl[itemHit]))
  2043.                     SetCtlValue(cntl[kItem_fDoTargaCheck],1);    /* must have output file option */
  2044.                 break;
  2045.             case kItem_fBtnThumbnail:    /* Thumbnail */
  2046.                 SetCtlValue(cntl[kItem_fDoTargaCheck],        0);    /* output file option */
  2047.                 SetCtlValue(cntl[kItem_fContinueTargaCheck],0);    /* Resume option */
  2048.                 SetCtlValue(cntl[kItem_fAntiAliasCheck],    0);        /* Antialias? */
  2049.                 SetIText((Handle) cntl[kItem_fImageWidth],    "\p32");        /* width */
  2050.                 SetIText((Handle) cntl[kItem_fImageHeight],    "\p32");        /* height */
  2051.                 SetIText((Handle) cntl[kItem_fRowFrom],        "\p0");        /* From */
  2052.                 SetIText((Handle) cntl[kItem_fRowTo],        "\p32");        /* To */
  2053.                 SetIText((Handle) cntl[kItem_fImageQuality],"\p9");        /* Quality */
  2054.                 SelIText(myDialog, kItem_fImageQuality, 0, 32767); /* select quality */
  2055.                 break;
  2056.             case kItem_fBtnPreview:   /* 320 x 240 Preview */
  2057.                 SetCtlValue(cntl[kItem_fDoTargaCheck],        0);    /* output file option */
  2058.                 SetCtlValue(cntl[kItem_fContinueTargaCheck],0);    /* Resume option */
  2059.                 SetCtlValue(cntl[kItem_fAntiAliasCheck],    0);        /* Antialias? */
  2060.                 SetIText((Handle) cntl[kItem_fImageWidth],    "\p320");    /* width */
  2061.                 SetIText((Handle) cntl[kItem_fImageHeight],    "\p240");    /* height */
  2062.                 SetIText((Handle) cntl[kItem_fRowFrom],        "\p0");        /* From */
  2063.                 SetIText((Handle) cntl[kItem_fRowTo],        "\p240");    /* To */
  2064.                 SetIText((Handle) cntl[kItem_fImageQuality],"\p9");        /* Quality */
  2065.                 if (file_settings->magniFactor > 2)
  2066.                     file_settings->magniFactor = 2;
  2067.                 SelIText(myDialog, kItem_fImageQuality, 0, 32767); /* select "quality" text */
  2068.                 break;
  2069.             case kItem_fBtnFullSize:  /* High Quality */
  2070.                 SetCtlValue(cntl[kItem_fDoTargaCheck],        1);    /* output file option */
  2071.                 SetCtlValue(cntl[kItem_fAntiAliasCheck],    1);        /* Antialias? */
  2072.                 SetIText((Handle) cntl[kItem_fImageWidth],    "\p640");    /* width */
  2073.                 SetIText((Handle) cntl[kItem_fImageHeight],    "\p480");    /* height */
  2074.                 SetIText((Handle) cntl[kItem_fRowFrom],        "\p0");        /* From */
  2075.                 SetIText((Handle) cntl[kItem_fRowTo],        "\p480");    /* To */
  2076.                 SetIText((Handle) cntl[kItem_fImageQuality],"\p9");        /* Quality */
  2077.                 SetIText((Handle) cntl[kItem_fAntiAliasThreshold],"\p0.1");    /* Antialias amount */
  2078.                 SelIText(myDialog, kItem_fAntiAliasThreshold, 0, 32767); /* select anti-alias amount */
  2079.                 if (file_settings->magniFactor > 1)
  2080.                     file_settings->magniFactor = 1;
  2081.                 break;
  2082.  
  2083.         }
  2084.     }
  2085.     while (itemHit != OK && itemHit != Cancel);
  2086.     
  2087.     if (itemHit != Cancel)
  2088.     {
  2089.         GetIText((Handle) cntl[kItem_fImageWidth], s1); sscanf(PtoCstr(s1) , "%hd", &file_settings->width);
  2090.         PinValue(&file_settings->width, 0, 4095);
  2091.         GetIText((Handle) cntl[kItem_fImageHeight], s1); sscanf(PtoCstr(s1) , "%hd", &file_settings->height);
  2092.         PinValue(&file_settings->height, 0, 4095);
  2093.         GetIText((Handle) cntl[kItem_fRowFrom], s1); sscanf(PtoCstr(s1) , "%hd", &file_settings->from);
  2094.         PinValue(&file_settings->from, 0, file_settings->height);
  2095.         GetIText((Handle) cntl[kItem_fRowTo], s1); sscanf(PtoCstr(s1) , "%hd", &file_settings->to);
  2096.         PinValue(&file_settings->to, file_settings->from, file_settings->height);
  2097.         GetIText((Handle) cntl[kItem_fImageQuality], s1); sscanf(PtoCstr(s1) , "%hd", &file_settings->quality);
  2098.         file_settings->antialias = GetCtlValue(cntl[kItem_fAntiAliasCheck]);
  2099.         GetIText((Handle) cntl[kItem_fAntiAliasThreshold], s1); sscanf(PtoCstr(s1) , "%lf", &file_settings->threshold);
  2100.         file_settings->cr_file = GetCtlValue(cntl[kItem_fDoTargaCheck]);
  2101.         file_settings->resume = GetCtlValue(cntl[kItem_fContinueTargaCheck]);
  2102.  
  2103.         if ( ((file_settings->to) < (file_settings->height)) || (file_settings->from) )
  2104.         {
  2105.             UseResFile(ourRefNum);
  2106.             myWarningDialog = GetNewDialog(131, NULL, (WindowPtr) -1);
  2107.             if (myWarningDialog)
  2108.             {
  2109.                 /* "default" the OK button */
  2110.                 SetupDefaultButton(myWarningDialog);
  2111.                 do
  2112.                     ModalDialog(NULL, &itemHit);
  2113.                 while (itemHit != OK && itemHit != Cancel);
  2114.  
  2115.                 if (itemHit == Cancel)
  2116.                 {
  2117.                     file_settings->to = file_settings->height;
  2118.                     file_settings->from = 0;
  2119.                 }
  2120.                 DisposDialog(myWarningDialog);
  2121.             }
  2122.             
  2123.         }
  2124.         WriteFileSettings();
  2125.     }
  2126.     DisposDialog(myDialog); myDialog = NULL;
  2127.     EnableItem(myMenus[1], 1); /* about box */
  2128.     EnableItem(myMenus[fmn_ID], 0); /* File menu */    
  2129.     EnableItem(myMenus[edmn_ID], edmn_undo); /* undo */
  2130.     DrawMenuBar();
  2131. }
  2132.  
  2133.  
  2134. void Render(void)
  2135. {
  2136.         char        s1[256], s2[256], *s2_p, *s3_p, c;
  2137.         int i;
  2138.     
  2139.         ARGC = 0;
  2140.         argptr = argstr;
  2141.         AddArg("POV");
  2142.         AddArg("+d0");
  2143.         AddArg("-p");
  2144.         AddArg("+ms500");
  2145.         /* option-Render will be verbose */
  2146.         if (myEvent.modifiers & optionKey)
  2147.             AddArg("+v");
  2148.         AddArg("-x");
  2149.         sprintf(s1, "-w%d", file_settings->width); AddArg(s1);
  2150.         sprintf(s1, "-h%d", file_settings->height); AddArg(s1);
  2151.         sprintf(s1, "-s%d", file_settings->from); AddArg(s1);
  2152.         sprintf(s1, "-e%d", file_settings->to); AddArg(s1);
  2153.         if (file_settings->antialias)
  2154.         {
  2155.             sprintf(s1, "+a%.3f", file_settings->threshold);
  2156.             AddArg(s1);
  2157.         }
  2158.         else
  2159.             AddArg("-a");
  2160.  
  2161.         sprintf(s1, "-q%d", file_settings->quality); AddArg(s1);
  2162.         if (file_settings->cr_file)
  2163.             AddArg("+ft");
  2164.         else
  2165.             AddArg("-f");
  2166.         AddArg(file_settings->resume ? "+c" : "-c");
  2167.  
  2168.         sprintf(s1, "-i%s", c_theFileName); AddArg(s1);
  2169.         
  2170.         strcpy(s2, c_theFileName);
  2171.  
  2172.         if (strstr(s2, ".POV"))
  2173.         {
  2174.             i = strlen(s2);
  2175.             s2[i - 4] = 0;
  2176.         }
  2177.             
  2178.         if (file_settings->cr_file)
  2179.         {
  2180.             strcat(s2, ".tga");
  2181.             strcpy(targaOutName, s2);
  2182.             sprintf(s1, "-o%s", s2); AddArg(s1);
  2183.         }
  2184.  
  2185.         /* Add -l options for library paths. */
  2186.         strcpy(s2, global_settings->paths);
  2187.         c = *s2;
  2188.         s3_p = s2_p = s2;
  2189.         while (c)
  2190.         {
  2191.             while (*s3_p && *s3_p != 13)
  2192.                 s3_p++;
  2193.             c = *s3_p;
  2194.             *s3_p = 0;
  2195.             /* Remove trailing ':'; POV takes care of appending that. */
  2196.             if (*(s3_p - 1) == ':')
  2197.                 *(s3_p - 1) = 0;
  2198.             if (*s2_p)
  2199.             {
  2200.                 sprintf(s1, "-l%s", s2_p);
  2201.                 AddArg(s1);
  2202.             }
  2203.             s2_p = ++s3_p;
  2204.         }
  2205.         
  2206.         SetVol(NULL, theVRefNum);
  2207.         Stop_Flag = 0;
  2208.         run_flag = 1;
  2209. }
  2210.  
  2211. void ChangeTargaType(void)
  2212. {
  2213.     OSErr i;
  2214.     FInfo myFileInfo;
  2215.     if (file_settings->cr_file)
  2216.     {
  2217.         CtoPstr(targaOutName);
  2218.         i = GetFInfo (targaOutName, theVRefNum, &myFileInfo);
  2219.         if (i==0)
  2220.         {
  2221.             myFileInfo.fdType = 'TPIC';
  2222.             myFileInfo.fdCreator = '8BIM';
  2223.             i = SetFInfo (targaOutName, theVRefNum, &myFileInfo);
  2224.         }
  2225.         PtoCstr(targaOutName);
  2226.     }
  2227. }
  2228.  
  2229. void inval_port_rect(void)
  2230. {
  2231.     Rect myInvalRect;
  2232.     if (plot_window)
  2233.     {
  2234.         SetPort(plot_window);
  2235.         myInvalRect.top = 0;
  2236.         myInvalRect.bottom = display_magniFactor * (global_y + 1);
  2237.         myInvalRect.left = 0;
  2238.         myInvalRect.right = display_magniFactor * global_width;
  2239.         InvalRect(&myInvalRect);
  2240.     }
  2241. }
  2242.  
  2243.  
  2244. /* post-processing */
  2245.  
  2246. void make_undo(void)
  2247. {
  2248.     if (undo_buffer == 0)
  2249.     {
  2250.         undo_buffer = NewPtr (global_bufsize);    /* room for image */
  2251.         undo_buffer2 = NewPtr (global_bufsize);    /* room for image */
  2252.         revert_buffer = NewPtr (global_bufsize);
  2253.         if ( (revert_buffer) && (plot_pixmap))
  2254.             memcpy (revert_buffer, plot_pixmap, global_bufsize);
  2255.     }
  2256.  
  2257. /* if any of the memory allocations failed, or available mem is low, fail the whole undo system */
  2258.     if ( (undo_buffer == 0) || (undo_buffer2 == 0) ||
  2259.          (revert_buffer == 0) || (FreeMem() < 20000L) )
  2260.     {
  2261.         if (undo_buffer) DisposePtr (undo_buffer);
  2262.         if (undo_buffer2) DisposePtr (undo_buffer2);
  2263.         if (revert_buffer) DisposePtr (revert_buffer);
  2264.         undo_buffer = 0;
  2265.         undo_buffer2 = 0;
  2266.         revert_buffer = 0;
  2267.     }
  2268.  
  2269.     if ((undo_buffer) && (plot_pixmap))
  2270.     {
  2271.         memcpy (undo_buffer, plot_pixmap, global_bufsize);
  2272.         undoable = TRUE;
  2273.     }
  2274. }
  2275.  
  2276. void undo(void)
  2277. {
  2278.     if ((undo_buffer) && (undoable) && (plot_pixmap))
  2279.     {
  2280.         memcpy (undo_buffer2, plot_pixmap, global_bufsize);
  2281.         memcpy (plot_pixmap, undo_buffer, global_bufsize);
  2282.         memcpy (undo_buffer, undo_buffer2, global_bufsize);
  2283.         inval_port_rect();
  2284.     }
  2285. }
  2286.  
  2287. void revert_image(void)
  2288. {
  2289.     if ((revert_buffer) && (plot_pixmap))
  2290.     {
  2291.         memcpy (undo_buffer, plot_pixmap, global_bufsize);
  2292.         memcpy (plot_pixmap, revert_buffer, global_bufsize);
  2293.         undoable = TRUE;
  2294.         inval_port_rect();
  2295.     }
  2296. }
  2297.  
  2298. short clipped_value(short v)
  2299. {
  2300.     if ( v < 0)
  2301.         return (0);
  2302.     if (v > 255)
  2303.         return (255);
  2304.     return (v);
  2305. }
  2306.  
  2307. void darken_image(void)
  2308. {
  2309.     unsigned char *pptr;
  2310.     long i,j;
  2311.     
  2312.     make_undo();
  2313.     if (plot_pixmap == 0) return;
  2314.  
  2315.     for (i=0; i < global_height; i++)
  2316.     {
  2317.         for (j=0; j < global_width; j++)
  2318.         {
  2319.             pptr = (unsigned char *) 
  2320.                     (plot_pixmap + 4L * ((global_width * i) + j));
  2321.             *pptr = 0;
  2322.             pptr++;
  2323.             *pptr = (*pptr * 7 / 8);
  2324.             pptr++;
  2325.             *pptr = (*pptr * 7 / 8);
  2326.             pptr++;
  2327.             *pptr = (*pptr * 7 / 8);
  2328.             pptr++;
  2329.         }
  2330.     }
  2331.     inval_port_rect();
  2332. }
  2333.  
  2334.  
  2335. void lighten_image(void)
  2336. {
  2337.     unsigned char *pptr;
  2338.     long i,j;
  2339.     short v;
  2340.  
  2341.     make_undo();
  2342.     if (plot_pixmap == 0) return;
  2343.  
  2344.     for (i=0; i < global_height; i++)
  2345.     {
  2346.         for (j=0; j < global_width; j++)
  2347.         {
  2348.             pptr = (unsigned char *) 
  2349.                     (plot_pixmap + 4L * ((global_width * i) + j));
  2350.             *pptr = 0;
  2351.             pptr++;
  2352.             v = (*pptr * 8 / 7);
  2353.             *pptr = clipped_value (v);
  2354.             pptr++;
  2355.             v = (*pptr * 8 / 7);
  2356.             *pptr = clipped_value (v);
  2357.             pptr++;
  2358.             v = (*pptr * 8 / 7);
  2359.             *pptr = clipped_value (v);
  2360.             pptr++;
  2361.         }
  2362.     }
  2363.     inval_port_rect();
  2364. }
  2365.  
  2366. void invert_image(void)
  2367. {
  2368.     unsigned char *pptr;
  2369.     long i,j;
  2370.     
  2371.     make_undo();
  2372.     if (plot_pixmap == 0) return;
  2373.  
  2374.     for (i=0; i < global_height; i++)
  2375.     {
  2376.         for (j=0; j < global_width; j++)
  2377.         {
  2378.             pptr = (unsigned char *) 
  2379.                     (plot_pixmap + 4L * ((global_width * i) + j));
  2380.             *pptr = 0;
  2381.             pptr++;
  2382.             *pptr = 255 - *pptr;
  2383.             pptr++;
  2384.             *pptr = 255 - *pptr;
  2385.             pptr++;
  2386.             *pptr = 255 - *pptr;
  2387.             pptr++;
  2388.         }
  2389.     }
  2390.     inval_port_rect();
  2391. }
  2392.  
  2393. void reduce_contrast(void)
  2394. {
  2395.     unsigned char *pptr;
  2396.     long i,j;
  2397.     short v;
  2398.     
  2399.     make_undo();
  2400.     if (plot_pixmap == 0) return;
  2401.  
  2402.     for (i=0; i < global_height; i++)
  2403.     {
  2404.         for (j=0; j < global_width; j++)
  2405.         {
  2406.             pptr = (unsigned char *) 
  2407.                     (plot_pixmap + 4L * ((global_width * i) + j));
  2408.             *pptr++ = 0;
  2409.  
  2410.             v = *pptr;
  2411.             v = v - ((v - 128) / 4);
  2412.             *pptr++ = v;
  2413.  
  2414.             v = *pptr;
  2415.             v = v - ((v - 128) / 4);
  2416.             *pptr++ = v;
  2417.  
  2418.             v = *pptr;
  2419.             v = v - ((v - 128) / 4);
  2420.             *pptr++ = v;
  2421.         }
  2422.     }
  2423.     inval_port_rect();
  2424. }
  2425.  
  2426.  
  2427. void increase_contrast(void)
  2428. {
  2429.     unsigned char *pptr;
  2430.     long i,j;
  2431.     short v;
  2432.  
  2433.     make_undo();
  2434.     if (plot_pixmap == 0) return;
  2435.  
  2436.     for (i=0; i < global_height; i++)
  2437.     {
  2438.         for (j=0; j < global_width; j++)
  2439.         {
  2440.             pptr = (unsigned char *) 
  2441.                     (plot_pixmap + 4L * ((global_width * i) + j));
  2442.             *pptr++ = 0;
  2443.  
  2444.             v = *pptr;
  2445.             v = v + ((v - 128) / 4);
  2446.             *pptr++ = clipped_value(v);
  2447.  
  2448.             v = *pptr;
  2449.             v = v + ((v - 128) / 4);
  2450.             *pptr++ = clipped_value(v);
  2451.  
  2452.             v = *pptr;
  2453.             v = v + ((v - 128) / 4);
  2454.             *pptr++ = clipped_value(v);
  2455.         }
  2456.     }
  2457.     inval_port_rect();
  2458. }
  2459.  
  2460.  
  2461. /* draw a black border around the edge of the image */
  2462. void draw_border(void)
  2463. {
  2464.     unsigned char *pptr;
  2465.     long i;
  2466.     
  2467.     make_undo();
  2468.     if (plot_pixmap == 0) return;
  2469.  
  2470.     for (i=0; i < global_height; i++)
  2471.     {
  2472. /* left border edge */
  2473.             pptr = (unsigned char *) 
  2474.                     (plot_pixmap + (global_width * 4 * i) );
  2475.             *pptr++ = 0;
  2476.             *pptr++ = 0;
  2477.             *pptr++ = 0;
  2478.             *pptr++ = 0;
  2479.  
  2480. /* right border edge */
  2481.             pptr = (unsigned char *) 
  2482.                     (plot_pixmap + (global_width * 4 * i) + ((global_width-1) * 4) );
  2483.             *pptr++ = 0;
  2484.             *pptr++ = 0;
  2485.             *pptr++ = 0;
  2486.             *pptr++ = 0;
  2487.     }
  2488.     for (i=0; i < global_width; i++)
  2489.     {
  2490. /* top border edge */
  2491.             pptr = (unsigned char *) 
  2492.                     (plot_pixmap + (4 * i));
  2493.             *pptr++ = 0;
  2494.             *pptr++ = 0;
  2495.             *pptr++ = 0;
  2496.             *pptr++ = 0;
  2497.  
  2498. /* bottom border edge */
  2499.             pptr = (unsigned char *) 
  2500.                     ( plot_pixmap + 4L*global_width*(global_height-1) + 4*i );
  2501.             *pptr++ = 0;
  2502.             *pptr++ = 0;
  2503.             *pptr++ = 0;
  2504.             *pptr++ = 0;
  2505.  
  2506.     }
  2507.     inval_port_rect();
  2508. }
  2509.  
  2510.  
  2511. void AboutPOV(void)
  2512. {
  2513.     Str31    appVers, compilerName;
  2514.  
  2515.     UseResFile(ourRefNum);
  2516.     myDialog = GetNewDialog(130, NULL, (WindowPtr) -1);
  2517.     if (myDialog)
  2518.     {
  2519.         GetAppVersionPString(1, appVers);
  2520.         GetCompilerNamePString(compilerName);
  2521.         ParamText(appVers, compilerName, "", "");
  2522.  
  2523.         /* Get into dialog's port & fiddle with fonts.. */
  2524.         SetPort((GrafPtr)myDialog);
  2525.         TextFont(geneva);
  2526.         TextSize(9);
  2527.         ShowWindow((WindowPtr)myDialog);
  2528.         /* "default" the OK button */
  2529.         SetupDefaultButton(myDialog);
  2530.         do
  2531.             ModalDialog(NULL, &itemHit);
  2532.         while (itemHit != 1);
  2533.         TextFont(geneva);
  2534.         TextSize(9);
  2535.         DisposDialog(myDialog);
  2536.     }
  2537.     myDialog = NULL;
  2538. }
  2539.  
  2540. void DisableMenus(void)
  2541. {
  2542.     int i;
  2543.     for (i = 2; i <= highest_menu; i++)
  2544.         DisableItem(myMenus[i], 0);
  2545.     DisableItem(myMenus[1], 1);
  2546.     DrawMenuBar();
  2547. }
  2548.  
  2549. void EnableMenus(void)
  2550. {
  2551.     int i;
  2552.     for (i = 2; i <= highest_menu; i++)
  2553.         EnableItem(myMenus[i], 0);
  2554.     EnableItem(myMenus[1], 1);
  2555.     DrawMenuBar();
  2556. }
  2557.  
  2558. void UpdateMenus(void)
  2559. {
  2560. short i;
  2561.  
  2562.     if (qd32_Available)                            
  2563.         EnableItem(myMenus[omn_ID], omn_dither);
  2564.     else
  2565.         DisableItem(myMenus[omn_ID], omn_dither);
  2566.  
  2567. /* Set the checking status of the "Options" menu */
  2568.     CheckItem(myMenus[omn_ID], omn_dither, (file_settings->ditherPaint && qd32_Available));
  2569.     CheckItem(myMenus[omn_ID], omn_shutdown, file_settings->request_shutdown);
  2570.  
  2571. /* Mark up the the WindowSize menu */
  2572.     CheckItem(mySubMenus[viewmn_ID],1,display_magniFactor == 0);
  2573.     CheckItem(mySubMenus[viewmn_ID],2,display_magniFactor == 1);
  2574.     CheckItem(mySubMenus[viewmn_ID],3,display_magniFactor == 2);
  2575.     CheckItem(mySubMenus[viewmn_ID],4,display_magniFactor == 3);
  2576.     CheckItem(mySubMenus[viewmn_ID],5,display_magniFactor == 4);
  2577.     CheckItem(mySubMenus[viewmn_ID],6,display_magniFactor == 5);
  2578.  
  2579. /* Enable individual Windows menu items */
  2580.     if (myp2windowIsUp)
  2581.         EnableItem(myMenus[wndmn_ID], 1);
  2582.     else
  2583.         DisableItem(myMenus[wndmn_ID], 1);
  2584.  
  2585.     if (window_visible)
  2586.         EnableItem(myMenus[wndmn_ID], 2);
  2587.     else
  2588.         DisableItem(myMenus[wndmn_ID], 2);
  2589.  
  2590.     if (plot_window)
  2591.         EnableItem(myMenus[wndmn_ID], 3);
  2592.     else
  2593.         DisableItem(myMenus[wndmn_ID], 3);
  2594.  
  2595.  
  2596. /* Enable the Edit menu */
  2597.     DisableItem(myMenus[edmn_ID], edmn_undo);
  2598.     DisableItem(myMenus[edmn_ID], edmn_cut);    
  2599.     DisableItem(myMenus[edmn_ID], edmn_copy);
  2600.     DisableItem(myMenus[edmn_ID], edmn_paste);
  2601.     DisableItem(myMenus[edmn_ID], edmn_clear);    
  2602.     DisableItem(myMenus[edmn_ID], edmn_redo);
  2603.     DisableItem(myMenus[edmn_ID], edmn_goto);
  2604.  
  2605.     if (FrontWindow() == TextEditWindow)
  2606.     {
  2607.         EnableItem(myMenus[edmn_ID], edmn_goto);
  2608.         if ((**TEH).selStart != (**TEH).selEnd)
  2609.         {
  2610.             EnableItem(myMenus[edmn_ID], edmn_cut);        
  2611.             EnableItem(myMenus[edmn_ID], edmn_copy);        
  2612.             EnableItem(myMenus[edmn_ID], edmn_clear);        
  2613.         }
  2614.         EnableItem(myMenus[edmn_ID], edmn_paste);        
  2615.         if (undo_record[max_undo].reason[0])
  2616.             EnableItem(myMenus[edmn_ID], edmn_undo);
  2617.         if (redo_record[max_undo].reason[0])
  2618.             EnableItem(myMenus[edmn_ID], edmn_redo);
  2619.     }    
  2620.  
  2621.     if (FrontWindow() == plot_window)
  2622.     {
  2623.         if (undoable)
  2624.             EnableItem(myMenus[edmn_ID], edmn_undo);
  2625.         if (plot_pixmap)
  2626.             EnableItem(myMenus[edmn_ID], edmn_copy);
  2627.     }
  2628.  
  2629. /* Enable the WindowSize menu */    
  2630.     if ((plot_pixmap) || (global_y < (global_height / 25)) || (run_flag == 0))
  2631.     {
  2632.         EnableItem(mySubMenus[viewmn_ID],1);
  2633.         EnableItem(mySubMenus[viewmn_ID],2);
  2634.         EnableItem(mySubMenus[viewmn_ID],3);
  2635.         EnableItem(mySubMenus[viewmn_ID],4);
  2636.         EnableItem(mySubMenus[viewmn_ID],5);
  2637.         EnableItem(mySubMenus[viewmn_ID],6);
  2638.     }
  2639.     else
  2640.     {
  2641.     /* don't let the user destroy his window unintentionally in the special case: 
  2642.     /* memory's so low that there's no pixmap for refresh */
  2643.         for (i=1; i <= 6; i++)
  2644.             DisableItem(mySubMenus[viewmn_ID], i);
  2645.     }
  2646.  
  2647. /* Enable the Image enhancement menu items */
  2648.     if ((plot_pixmap) && (virtual_file == 0) && (run_flag == 0))
  2649.         for (i=immn_border; i <= immn_revert; i++)
  2650.             EnableItem(myMenus[immn_ID], i);
  2651.     else
  2652.         for (i=immn_border; i <= immn_revert; i++)
  2653.             DisableItem(myMenus[immn_ID], i);
  2654. /* specifically disable the separator lines */
  2655.     DisableItem(myMenus[immn_ID],immn_divider1);
  2656.     DisableItem(myMenus[immn_ID],immn_divider2);
  2657.     DisableItem(myMenus[immn_ID],immn_divider3);
  2658.  
  2659.  
  2660. /* Enable File Menu items */
  2661.     if ((plot_window != 0) || (window_visible == TRUE))
  2662.         EnableItem(myMenus[fmn_ID], fmn_close); /* Close */
  2663.     else
  2664.         DisableItem(myMenus[fmn_ID],fmn_close);
  2665.  
  2666.     if (myDialog == 0)
  2667.     {
  2668.         if (POV_running)
  2669.         {
  2670.             if (FrontWindow() == TextEditWindow)
  2671.                 DisableItem(myMenus[2], fmn_close);    /* don't allow close during render */
  2672.             DisableItem(myMenus[1], 1); /* about box */
  2673.             DisableItem(myMenus[fmn_ID], fmn_open); /* Open file */
  2674.             DisableItem(myMenus[fmn_ID], fmn_new); /* New file */
  2675.             DisableItem(myMenus[fmn_ID], fmn_render); /* Render */
  2676.             DisableItem(myMenus[fmn_ID], fmn_newopts); /* new options */
  2677.             if ((window_visible) && (FrontWindow() == TextEditWindow) && (dirty))
  2678.                 EnableItem(myMenus[fmn_ID], fmn_savetext); /* Save is okay */
  2679.             else
  2680.                 DisableItem(myMenus[fmn_ID], fmn_savetext);
  2681.             DisableItem(myMenus[fmn_ID], fmn_saveas); /* Save as╔ */
  2682.             EnableItem(myMenus[fmn_ID], fmn_pause);    /* pause trace */
  2683.             EnableItem(myMenus[fmn_ID], fmn_stop);    /* abort trace */
  2684.             DisableItem(myMenus[fmn_ID], fmn_savepict); /* Save output as╔ */
  2685.         }
  2686.         else
  2687.         {
  2688.             EnableItem(myMenus[1], 1); /* about box */
  2689.             DisableItem(myMenus[fmn_ID], fmn_render); /* Render */
  2690.             DisableItem(myMenus[fmn_ID], fmn_newopts); /* new options */
  2691.             if (window_visible)
  2692.             {
  2693.                 EnableItem(myMenus[fmn_ID], fmn_saveas); /* Save as╔ */
  2694.                 if (c_theFileName[0])
  2695.                 {
  2696.                     EnableItem(myMenus[fmn_ID], fmn_newopts); /* new options */
  2697.                     EnableItem(myMenus[fmn_ID], fmn_render); /* Render */
  2698.                 }
  2699.             }
  2700.             else
  2701.             {
  2702.                 DisableItem(myMenus[2], fmn_saveas); /* Save as╔ */
  2703.             }
  2704.             
  2705.             if ((window_visible) && (dirty))
  2706.             {
  2707.                 EnableItem(myMenus[fmn_ID], fmn_savetext); /* Save */
  2708.                 DisableItem(myMenus[fmn_ID], fmn_new); /* New file */
  2709.                 DisableItem(myMenus[fmn_ID], fmn_open); /* Open file */
  2710.             }
  2711.             else
  2712.             {
  2713.                 EnableItem(myMenus[fmn_ID], fmn_new); /* New file */
  2714.                 EnableItem(myMenus[fmn_ID], fmn_open); /* Open file */
  2715.                 DisableItem(myMenus[fmn_ID], fmn_savetext); /* Save */
  2716.             }
  2717.  
  2718.             DisableItem(myMenus[fmn_ID], fmn_pause);    /* pause trace */
  2719.             DisableItem(myMenus[fmn_ID], fmn_stop);    /* abort trace */
  2720.  
  2721.  
  2722.             if ((plot_pixmap) && (display_magniFactor))
  2723.                 EnableItem(myMenus[fmn_ID], fmn_savepict); /* Save output as╔ */
  2724.             else        
  2725.                 DisableItem(myMenus[fmn_ID], fmn_savepict);
  2726.         }
  2727.     }
  2728. }
  2729.  
  2730. void ask_about_quit(void)
  2731. {
  2732.     if    ( (file_settings->cr_file == 0) && (run_flag) )
  2733.     {
  2734.         UseResFile(ourRefNum);
  2735.         myDialog = GetNewDialog (137, NULL, (WindowPtr) -1);
  2736.         /* "default" the OK button */
  2737.         SetupDefaultButton(myDialog);
  2738.         do
  2739.         {
  2740.             ModalDialog(NULL, &itemHit);
  2741.             if (itemHit == 1)
  2742.                 Stop_Flag = quit_flag = 1;
  2743.         }
  2744.         while (itemHit != 1 && itemHit != 2);
  2745.         DisposDialog (myDialog); myDialog = NULL;
  2746.     }
  2747.     else
  2748.         Stop_Flag = quit_flag = 1;
  2749. }
  2750.  
  2751. void ask_about_stop(void)
  2752. {
  2753.     UseResFile(ourRefNum);
  2754.     if    (file_settings->cr_file)
  2755.         myDialog = GetNewDialog (135, NULL, (WindowPtr) -1);
  2756.     else
  2757.         myDialog = GetNewDialog (134, NULL, (WindowPtr) -1);
  2758.     /* "default" the OK button */
  2759.     SetupDefaultButton(myDialog);
  2760.     do
  2761.     {    
  2762.         ModalDialog(NULL, &itemHit);
  2763.         if (itemHit == 1)
  2764.             Stop_Flag = 1;
  2765.         if ((itemHit == 2) && (file_settings->cr_file))
  2766.             itemHit = 3;
  2767.     }
  2768.     while    (itemHit != 1 && itemHit != 2);
  2769.     DisposDialog (myDialog); myDialog = NULL;
  2770. }
  2771.     
  2772.  
  2773. void pause_it(void)
  2774. {
  2775.  
  2776.     if (pause_flag == 1)
  2777.         pause_flag = 2;
  2778.     else
  2779.     {
  2780.         pause_flag = 1;
  2781.         HiliteMenu(0);
  2782.         DisableItem(myMenus[1], 1); /* about box */
  2783.         DisableItem(myMenus[edmn_ID], 0); /* Edit menu */
  2784.         DisableItem(myMenus[omn_ID], 0); /* Options menu */
  2785.         CheckItem(myMenus[2],fmn_pause,1);
  2786.     
  2787.         do
  2788.             MacDawdle();
  2789.         while ((Stop_Flag == 0) && (pause_flag != 2));
  2790.     
  2791.         EnableItem(myMenus[1], 1); /* about box */
  2792.         EnableItem(myMenus[edmn_ID], 0); /* Edit menu */
  2793.         EnableItem(myMenus[omn_ID], 0); /* Options menu */
  2794.         CheckItem(myMenus[2],fmn_pause,0);
  2795.         DrawMenuBar();
  2796.         pause_flag = 0;
  2797.     }
  2798. }
  2799.  
  2800.  
  2801. void Activate(WindowPtr theWindow)
  2802. {
  2803. /* Show the window controls */
  2804.     if (theWindow)
  2805.     {
  2806.         SelectWindow(theWindow);
  2807.         if (theWindow == TextEditWindow)
  2808.         {
  2809.             TEActivate(TEH);
  2810.             ShowControl(vScroll);
  2811.             TEFromScrap();
  2812.         }
  2813.     }
  2814. }
  2815.  
  2816. void Deactivate(WindowPtr theWindow)
  2817. {
  2818. /* Hide the window controls */
  2819.     if ((theWindow == TextEditWindow) && (TextEditWindow != 0))
  2820.     {
  2821.         TEDeactivate(TEH);
  2822.         HideControl(vScroll);
  2823.         ZeroScrap();
  2824.         TEToScrap();
  2825.     }
  2826. }
  2827.  
  2828.  
  2829. OSErr MyDirID2VrefNum(short vRefNum, long dirID, short *theWDVrefNumPtr)
  2830. {
  2831.     OSErr            anError;
  2832.  
  2833.     // Open a Working directory for ourselves.  Note that we leave
  2834.     // it open forever (just like SFGetFile does.)  This is supposed
  2835.     // to be kosher..
  2836.     anError = OpenWD(vRefNum, dirID, kAppSignature, theWDVrefNumPtr);
  2837.     return anError;
  2838. }
  2839.  
  2840.  
  2841. void OpenTextFile(Str255 fn, short vRef, long dirID, Boolean UseDirID)
  2842. {
  2843.     short    refNum;
  2844.     Rect    oldHorizBar;
  2845.     Rect     r;
  2846.     int        errcode = noErr;
  2847.  
  2848.     /* If ODOC, find working dir from vref/dirID so we can use FSOpen etc. */
  2849.     if (UseDirID)
  2850.     {
  2851.         /* convert vref/dirID into WD vrefnum for later FSOpen and SetVol calls */
  2852.         errcode = MyDirID2VrefNum(vRef, dirID, &theVRefNum);
  2853.     }
  2854.     else
  2855.     {
  2856.         theVRefNum = vRef;
  2857.     }
  2858.     if (errcode==noErr)
  2859.         errcode = FSOpen(fn, theVRefNum, &refNum);
  2860.     if (errcode==noErr)
  2861.     {
  2862.         flush_undo_system();
  2863.         errcode = ReadFile(refNum, TEH);
  2864.         if (errcode == 1) 
  2865.         {
  2866.             pStrCopy(fn, theFileName);
  2867.             PtoCstr(theFileName);
  2868.             strcpy(c_theFileName, (char *) theFileName);
  2869.             CtoPstr(theFileName);
  2870.             SetWTitle(TextEditWindow, theFileName);
  2871.             dirty = 0;
  2872.         }
  2873.         if (errcode == 999)
  2874.             FileError("\pFile too large to be edited: ", fn);
  2875.         FSClose(refNum);    /* and ignore close errors */
  2876.         if (errcode == 1)
  2877.         {
  2878.             GetFileSettings();
  2879.             SetPort(TextEditWindow);
  2880. // JIM!  What is this oldHorizBar code for? Shouldn't this be AFTER we resize the window?
  2881. // doesn't the later InvalRect() code force a complete window update anyway?
  2882. // Eduard!  Beats me!  I'm just a victim of monkey-see monkey-do.
  2883.             oldHorizBar = TextEditWindow->portRect;
  2884.             oldHorizBar.top = oldHorizBar.bottom - (SBarWidth+1);
  2885.             SizeWindow(TextEditWindow, 
  2886.                         file_settings->srcWind_pos.right-file_settings->srcWind_pos.left,
  2887.                         file_settings->srcWind_pos.bottom-file_settings->srcWind_pos.top, false);
  2888.             MoveWindow(TextEditWindow, 
  2889.                         file_settings->srcWind_pos.left,
  2890.                         file_settings->srcWind_pos.top, false);
  2891.             InvalRect(&TextEditWindow->portRect);
  2892.  
  2893.             SetView(TextEditWindow);
  2894.             EraseRect(&oldHorizBar);
  2895.  
  2896.             MoveControl(vScroll, TextEditWindow->portRect.right - SBarWidth, 
  2897.                         TextEditWindow->portRect.top-1);
  2898.             SizeControl(vScroll, SBarWidth+1, 
  2899.                         TextEditWindow->portRect.bottom - TextEditWindow->portRect.top-(SBarWidth-2));
  2900.             r = (**vScroll).contrlRect;
  2901.             ValidRect(&r);        
  2902.             AdjustText();
  2903.  
  2904.             ShowWindow(TextEditWindow);
  2905.             window_visible = TRUE;
  2906.             TESetSelect(0, 0, TEH);
  2907.             ShowSelect();
  2908.             SelectWindow(TextEditWindow);
  2909.         }
  2910.     }
  2911.     else
  2912.         FileError("\pError opening ", fn);
  2913.  
  2914.     EnableItem(myMenus[1], 1); /* about box */
  2915.     EnableItem(myMenus[2], 0); /* File menu */
  2916.     EnableItem(myMenus[edmn_ID], edmn_undo); /* undo */
  2917.     DrawMenuBar();
  2918. }
  2919.  
  2920. short free_undo_memory(void)
  2921. {
  2922.     short    i;
  2923.     /* from the oldest to newest (except the last), dispose the Undo & redo buffers */
  2924.     for (i = 0; i < max_undo; i++)
  2925.     {
  2926.         if (redo_record[i].buf_handle)
  2927.         {
  2928.             DisposeHandle(redo_record[i].buf_handle);
  2929.             redo_record[i].buf_handle = 0;
  2930.             redo_record[i].reason[0] = 0;
  2931.             return (1);
  2932.         }            
  2933.         if (undo_record[i].buf_handle)
  2934.         {
  2935.             DisposeHandle(undo_record[i].buf_handle);
  2936.             undo_record[i].buf_handle = 0;
  2937.             undo_record[i].reason[0] = 0;
  2938.             return (1);
  2939.         }
  2940.     }
  2941.     return (0);
  2942. }
  2943.  
  2944. /* Support undo by duplicating the current file's text as necessary */
  2945. void support_undo(char *the_reason, short flush_redo)
  2946. {
  2947.     int i;
  2948.     char *buffer;
  2949.  
  2950. /* new changes are being made to the file.  Redo no longer makes sense. */
  2951.     if (flush_redo)
  2952.         flush_redo_system();
  2953.  
  2954. /* Dispose oldest undo record storage, because the record will be destroyed. */
  2955.     if (undo_record[0].buf_handle)
  2956.         DisposeHandle(undo_record[0].buf_handle);
  2957.  
  2958. /* block-move the records down to make room for a new undo entry */
  2959.     for (i = 0; i < max_undo; i++)
  2960.         undo_record[i] = undo_record[i+1];
  2961.  
  2962. /* Try repeatedly to allocate memory for the undo buffer, disposing old */
  2963. /* undo buffers as necessary. */
  2964.  
  2965. TRY_AGAIN:
  2966.     undo_record[max_undo].buf_handle = (char **) NewHandle((**TEH).teLength);
  2967.     if (undo_record[max_undo].buf_handle == 0)
  2968.         if (free_undo_memory()) goto TRY_AGAIN;
  2969.  
  2970.     if (undo_record[max_undo].buf_handle == 0)
  2971.     {
  2972.         undo_record[max_undo].reason[0] = 0;
  2973.         return;
  2974.     }
  2975.     HLock(undo_record[max_undo].buf_handle);
  2976.     buffer = *(undo_record[max_undo].buf_handle);
  2977.     undo_record[max_undo].selStart = (**TEH).selStart;
  2978.     undo_record[max_undo].selEnd = (**TEH).selEnd;
  2979.     strcpy(undo_record[max_undo].reason, the_reason);
  2980.     strcpy(undo_menu_name, "Undo ");
  2981.     strcat(undo_menu_name, the_reason);
  2982.     CtoPstr(undo_menu_name);
  2983.     SetItem(myMenus[edmn_ID], edmn_undo, undo_menu_name);
  2984.     undo_record[max_undo].byteCount = (**TEH).teLength;
  2985.     undo_record[max_undo].dirty = dirty;
  2986.     memcpy(buffer, *(**TEH).hText, (**TEH).teLength);
  2987.     HUnlock(undo_record[max_undo].buf_handle);
  2988.     undo_key_copied = 0;
  2989. }
  2990.  
  2991.  
  2992. /* Support redo by duplicating the current file's text as necessary */
  2993. void support_redo(char *the_reason)
  2994. {
  2995.     int i;
  2996.     char *buffer;
  2997.  
  2998. /* Dispose oldest redo record storage, because the record will be destroyed. */
  2999.     if (redo_record[0].buf_handle)
  3000.         DisposeHandle(redo_record[0].buf_handle);
  3001.  
  3002. /* block-move the records down to make room for a new redo entry */
  3003.     for (i = 0; i < max_undo; i++)
  3004.         redo_record[i] = redo_record[i+1];
  3005.  
  3006. /* Try repeatedly to allocate memory for the redo buffer, disposing old */
  3007. /* redo buffers as necessary. */
  3008. TRY_AGAIN:
  3009.     redo_record[max_undo].buf_handle = (char **) NewHandle((**TEH).teLength);
  3010.     if (redo_record[max_undo].buf_handle == 0)
  3011.         if (free_undo_memory()) goto TRY_AGAIN;
  3012.  
  3013.     if (redo_record[max_undo].buf_handle == 0)
  3014.     {
  3015.         redo_record[max_undo].reason[0] = 0;
  3016.         return;
  3017.     }
  3018.     HLock(redo_record[max_undo].buf_handle);
  3019.     buffer = *(redo_record[max_undo].buf_handle);
  3020.     redo_record[max_undo].selStart = (**TEH).selStart;
  3021.     redo_record[max_undo].selEnd = (**TEH).selEnd;
  3022.     strcpy(redo_record[max_undo].reason, the_reason);
  3023.     strcpy(redo_menu_name, "Redo ");
  3024.     strcat(redo_menu_name, the_reason);
  3025.     CtoPstr(redo_menu_name);
  3026.     SetItem(myMenus[edmn_ID], edmn_redo, redo_menu_name);
  3027.     redo_record[max_undo].byteCount = (**TEH).teLength;
  3028.     redo_record[max_undo].dirty = dirty;
  3029.     memcpy(buffer, *(**TEH).hText, (**TEH).teLength);
  3030.     HUnlock(redo_record[max_undo].buf_handle);
  3031. }
  3032.  
  3033. void support_undo_key(void)
  3034. {
  3035.     if (undo_key_copied == 0)
  3036.     {
  3037.         support_undo("Typing", TRUE);
  3038.         undo_key_copied = 1;
  3039.     }
  3040. }
  3041.  
  3042. void undo_text()
  3043. {
  3044.     int i;
  3045.     char *buffer;
  3046.     if (undo_record[max_undo].reason[0])
  3047.     {
  3048.         support_redo(undo_record[max_undo].reason);
  3049.         (**TEH).selStart = 0;
  3050.         (**TEH).selEnd = (**TEH).teLength;
  3051.         TEDelete(TEH);
  3052.         HLock(undo_record[max_undo].buf_handle);
  3053.         buffer = *(undo_record[max_undo].buf_handle);
  3054.         TEInsert(buffer, undo_record[max_undo].byteCount, TEH);
  3055.         undo_key_copied = 0;
  3056.         TESetSelect(undo_record[max_undo].selStart, undo_record[max_undo].selEnd, TEH);
  3057.         dirty = undo_record[max_undo].dirty;
  3058.         InvalRect(&TextEditWindow->portRect);
  3059.         /* dispose of the current undo record's data */
  3060.         DisposeHandle(undo_record[max_undo].buf_handle);
  3061.         /* move other undo records up the chain. */
  3062.         for (i = max_undo; i > 0; i--)
  3063.             undo_record[i] = undo_record[i-1];
  3064.         /* Delete the contents of the (duplicated) last record */
  3065.         undo_record[0].buf_handle = 0;
  3066.         undo_record[0].reason[0] = 0;
  3067.         /* show everyone what the next undoable item will be */
  3068.         strcpy(undo_menu_name, "Undo ");
  3069.         strcat(undo_menu_name, undo_record[max_undo].reason);
  3070.         CtoPstr(undo_menu_name);
  3071.         SetItem(myMenus[edmn_ID], edmn_undo, undo_menu_name);
  3072.     }
  3073. }
  3074.  
  3075. void redo_text()
  3076. {
  3077.     int i;
  3078.     char *buffer;
  3079.     if (redo_record[max_undo].reason[0])
  3080.     {
  3081.         support_undo(redo_record[max_undo].reason, FALSE);
  3082.         (**TEH).selStart = 0;
  3083.         (**TEH).selEnd = (**TEH).teLength;
  3084.         TEDelete(TEH);
  3085.         HLock(redo_record[max_undo].buf_handle);
  3086.         buffer = *(redo_record[max_undo].buf_handle);
  3087.         TEInsert(buffer, redo_record[max_undo].byteCount, TEH);
  3088.         undo_key_copied = 0;
  3089.         TESetSelect(redo_record[max_undo].selStart, redo_record[max_undo].selEnd, TEH);
  3090.         dirty = redo_record[max_undo].dirty;
  3091.         /* dispose of the current undo record's data */
  3092.         DisposeHandle(redo_record[max_undo].buf_handle);
  3093.         /* move other undo records up the chain. */
  3094.         for (i = max_undo; i > 0; i--)
  3095.             redo_record[i] = redo_record[i-1];
  3096.         /* Delete the contents of the (duplicated) last record */
  3097.         redo_record[0].buf_handle = 0;
  3098.         redo_record[0].reason[0] = 0;
  3099.         /* show everyone what the next redoable item will be */
  3100.         strcpy(redo_menu_name, "Redo ");
  3101.         strcat(redo_menu_name, redo_record[max_undo].reason);
  3102.         CtoPstr(redo_menu_name);
  3103.         SetItem(myMenus[edmn_ID], edmn_redo, redo_menu_name);
  3104.     }
  3105. }
  3106.  
  3107.  
  3108. void init_undo_system()
  3109. {
  3110.     int i;
  3111.     for (i = 0; i <= max_undo; i++)
  3112.     {
  3113.         undo_record[i].buf_handle = 0;
  3114.         undo_record[i].reason[0] = 0;
  3115.     }
  3116.     undo_key_copied = 0;
  3117. }
  3118.  
  3119. void flush_undo_system()
  3120. {
  3121.     int i;
  3122.     for (i = 0; i <= max_undo; i++)
  3123.     {
  3124.         if (undo_record[i].buf_handle)
  3125.         {
  3126.             DisposeHandle(undo_record[i].buf_handle);
  3127.             undo_record[i].buf_handle = 0;
  3128.         }
  3129.         undo_record[i].reason[0] = 0;
  3130.     }
  3131.     undo_key_copied = 0;
  3132. }
  3133.  
  3134. void init_redo_system()
  3135. {
  3136.     int i;
  3137.     for (i = 0; i <= max_undo; i++)
  3138.     {
  3139.         redo_record[i].buf_handle = 0;
  3140.         redo_record[i].reason[0] = 0;
  3141.     }
  3142. }
  3143.  
  3144. void flush_redo_system()
  3145. {
  3146.     int i;
  3147.     for (i = 0; i <= max_undo; i++)
  3148.     {
  3149.         if (redo_record[i].buf_handle)
  3150.         {
  3151.             DisposeHandle(redo_record[i].buf_handle);
  3152.             redo_record[i].buf_handle = 0;
  3153.         }
  3154.         redo_record[i].reason[0] = 0;
  3155.     }
  3156. }
  3157.  
  3158.  
  3159. void DoFile_New(void)
  3160. {
  3161.     if ((run_flag == 0) && (window_visible == FALSE))
  3162.     {
  3163.         SetWTitle(TextEditWindow, "\pUntitled");
  3164.         ShowWindow(TextEditWindow);
  3165.         window_visible = TRUE;
  3166.         dirty = 0;
  3167.     }
  3168. } // DoFile_New
  3169.  
  3170.  
  3171. void DoFile_Open(void)
  3172. {
  3173.     short    vRef;
  3174.     Str255     fn;
  3175.  
  3176.     if (run_flag == 0)
  3177.         if (OldFile(fn, &vRef))
  3178.             OpenTextFile(fn, vRef, 0L, false/*!UseDirID*/);                
  3179. } // DoFile_Open
  3180.  
  3181.  
  3182. void DoFileMenu(short theItem)
  3183. {
  3184.     switch (theItem)
  3185.     {
  3186.         case fmn_new:                                /* New File */
  3187.                 DoFile_New();
  3188.                 break;
  3189.  
  3190.         case fmn_open:                                 /* Open a file */
  3191.                 DoFile_Open();
  3192.                 break;
  3193.         case fmn_close:                                /* Close */
  3194.                 if (FrontWindow() == plot_window)
  3195.                 {
  3196.                     DisposeWindow(plot_window); 
  3197.                     plot_window = NULL;
  3198.                     display_magniFactor = 0;
  3199.                 }
  3200.                 else if (FrontWindow() == TextEditWindow)
  3201.                 {
  3202.                     DoFile(fmn_close);
  3203.                 }
  3204.                 break;
  3205.         case fmn_savetext:                            /* Save */
  3206.                 if ((TextEditWindow) && (window_visible))
  3207.                 {    
  3208.                     DoFile(fmn_savetext);
  3209.                     /* set up c string to enable other menu options */ 
  3210.                     PtoCstr(theFileName);                            
  3211.                     strcpy(c_theFileName, (char *) theFileName);    
  3212.                     CtoPstr(theFileName);                            
  3213.                     WriteFileSettings();                            
  3214.                 }                                                    
  3215.                 break;
  3216.         case fmn_saveas:                            /* Save as╔ */
  3217.                     DoFile(fmn_saveas);
  3218.                     /* set up c string to enable other menu options */ 
  3219.                     PtoCstr(theFileName);                            
  3220.                     strcpy(c_theFileName, (char *) theFileName);    
  3221.                     CtoPstr(theFileName);                            
  3222.                     GetFileSettings();                                
  3223.                 break;
  3224.         case fmn_render:                            /* Render */
  3225.                 DoFile(fmn_render);
  3226.                 if (c_theFileName)
  3227.                 {
  3228.                     if (myp2window)
  3229.                     {
  3230.                         ShowWindow((WindowPtr)myp2window);
  3231.                         myp2windowIsUp = true;
  3232.                         SelectWindow((WindowPtr)myp2window);
  3233.                     }
  3234.                     Render();
  3235.                 }
  3236.                 break;
  3237.         case fmn_newopts:                             /* Change options */
  3238.                 if ((run_flag == 0) && (fileResRefNum != -1) && (window_visible))
  3239.                     ChangeFileSettings();
  3240.                 break;
  3241.         case fmn_pause:                                /* pause trace */
  3242.                 pause_it();
  3243.                 break;    
  3244.         case fmn_stop:                                /* Abort trace in progress? */
  3245.                 ask_about_stop();
  3246.                 break;        
  3247.         case fmn_savepict:                            /* Save output as╔ */
  3248.                 saveOutputFile(true);
  3249.                 break;    
  3250.         case fmn_prefs:
  3251.                 ChangeGlobalSettings();
  3252.                 break;                                 /* Preferences╔ */
  3253.         case fmn_quit:
  3254.                 if (DoFile(fmn_close))
  3255.                     ask_about_quit();
  3256.                 break;    /* Quit the program */
  3257.     }
  3258. }
  3259.  
  3260.  
  3261. void DoEditMenu(short theItem)
  3262. {
  3263.  
  3264.     if (SystemEdit(theItem-1) != 0)
  3265.         return;
  3266.  
  3267. /* Edit menu for dialogs */
  3268.     if (myDialog)
  3269.     {
  3270.         switch (theItem)
  3271.         {
  3272.             case edmn_cut: DlgCut(myDialog); break;
  3273.             case edmn_copy: DlgCopy(myDialog); break;
  3274.             case edmn_paste: DlgPaste(myDialog); break;
  3275.             case edmn_clear: DlgDelete(myDialog); break;
  3276.         }
  3277.     }
  3278.  
  3279. /* Edit menu for text editor */
  3280.     if (FrontWindow() == TextEditWindow)
  3281.     {
  3282.         switch (theItem)
  3283.         {
  3284.             case edmn_undo:
  3285.                 undo_text();
  3286.                 AdjustText();
  3287.                 break;
  3288.  
  3289.             case edmn_cut:
  3290.                 support_undo("Cut", TRUE);
  3291.                 TECut(TEH);
  3292.                 AdjustText();
  3293.                 dirty = 1;
  3294.                 break;
  3295.  
  3296.             case edmn_copy:
  3297.                 TECopy(TEH);
  3298.                 break;
  3299.     
  3300.             case edmn_paste:
  3301.                 support_undo("Paste", TRUE);
  3302.                 TEPaste(TEH);
  3303.                 AdjustText();
  3304.                 dirty = 1;
  3305.                 break;
  3306.     
  3307.             case edmn_clear:
  3308.                 support_undo("Clear", TRUE);
  3309.                 TEDelete(TEH);
  3310.                 AdjustText();
  3311.                 dirty = 1;
  3312.                 break;
  3313.             case edmn_redo:
  3314.                 redo_text();
  3315.                 AdjustText();
  3316.                 break;
  3317.             case edmn_goto:
  3318.                 choose_goto_line();
  3319.         }
  3320.     }
  3321.  
  3322. /* Edit menu for output image window */
  3323.     if (FrontWindow() == plot_window)
  3324.     {                        
  3325.         switch (theItem)
  3326.         {
  3327.             case edmn_undo:
  3328.                 if (undoable)                    /*undo*/
  3329.                     undo();
  3330.                 break;
  3331.             case edmn_copy:
  3332.                 if (plot_pixmap)                /*copy*/
  3333.                     paint_to_picture(FALSE);
  3334.                 break;
  3335.         }
  3336.     }
  3337. }
  3338.  
  3339. void DoCommand(long m)
  3340. {
  3341.     short    theMenu, theItem;
  3342.     Str255    name;
  3343.  
  3344.     Rect    brect;
  3345.  
  3346.     theMenu = (m >> 16) - 127;
  3347.     theItem = m;
  3348.     switch (theMenu)
  3349.     {
  3350.         case 1:
  3351.             if (theItem == 1)
  3352.                 AboutPOV();
  3353.             else
  3354.             {
  3355.                 GetItem(myMenus[1], theItem, name);
  3356.                 OpenDeskAcc(name);
  3357.             }
  3358.             break;
  3359.             
  3360.         case 2:
  3361.             DoFileMenu(theItem);
  3362.             break;
  3363.  
  3364.         case 3:
  3365.             DoEditMenu(theItem);
  3366.             break;
  3367.         case 4:
  3368.             switch (theItem)
  3369.             {
  3370.                 case omn_dither:
  3371.                         file_settings->ditherPaint = !file_settings->ditherPaint;
  3372.                         inval_port_rect();
  3373.                         break;
  3374.                 case omn_shutdown:
  3375.                         file_settings->request_shutdown = !file_settings->request_shutdown;
  3376.                         if ((run_flag) && (file_settings->request_shutdown))
  3377.                             error_dialog(148);
  3378.             }
  3379.             break;
  3380.         case 200-128+viewmn_ID:
  3381.             file_settings->magniFactor = theItem - 1;
  3382.             if (myDialog == 0)
  3383.             {
  3384.                 display_magniFactor = file_settings->magniFactor;
  3385.                 if (display_magniFactor == 5)
  3386.                     display_magniFactor = 8;
  3387.                 if (plot_window)
  3388.                     DisposeWindow(plot_window); 
  3389.                 plot_window = NULL;
  3390.                 if ( (display_magniFactor) && (plot_pixmap) )
  3391.                 {
  3392.                     SetRect(&disp_plot_bounds, 0, 0,
  3393.                                 global_width * display_magniFactor,
  3394.                                 global_height * display_magniFactor);
  3395.                     brect = disp_plot_bounds;
  3396.                     OffsetRect(&brect,
  3397.                                 file_settings->imageWind_pos.left,
  3398.                                 file_settings->imageWind_pos.top);    
  3399.  
  3400.                     plot_window = NewCWindow(NULL, &brect, theFileName, true,
  3401.                                             noGrowDocProc, (WindowPtr) -1L, false, 0);
  3402.                 }
  3403.             }
  3404.             break;
  3405.  
  3406.         case immn_ID:
  3407.             switch (theItem)
  3408.             {
  3409.                 case immn_border: draw_border(); break;
  3410.                 case immn_darken: darken_image(); break;
  3411.                 case immn_lighten: lighten_image(); break;
  3412.                 case immn_reduceC: reduce_contrast(); break;
  3413.                 case immn_increaseC: increase_contrast(); break;
  3414.                 case immn_invert: invert_image(); break;
  3415.                 case immn_revert: revert_image(); break;
  3416.             }
  3417.             break;
  3418.         case wndmn_ID: /* Windows menu */
  3419.             switch (theItem)
  3420.             {
  3421.                 case 1: if (myp2windowIsUp)
  3422.                         {
  3423.                             SelectWindow((WindowPtr)myp2window);
  3424.                         }
  3425.                         break;
  3426.                 case 2: if ((TextEditWindow) && (window_visible))
  3427.                         {    /* be thorough */
  3428.                             ShowWindow(TextEditWindow);
  3429.                             SelectWindow(TextEditWindow);
  3430.                         }
  3431.                         break;
  3432.                 case 3: if (plot_window)
  3433.                         {
  3434.                             SelectWindow(plot_window);
  3435.                         }
  3436.                         break;
  3437.             }
  3438.             break;
  3439.     }
  3440.     HiliteMenu(0);
  3441. }
  3442.  
  3443. void DoMouseDown(void)
  3444. {
  3445.     short            code, part;
  3446.     WindowPtr        whichWindow;
  3447.     ControlHandle    whichControl;
  3448.     Rect            theWindowPos;    
  3449.  
  3450.     code = FindWindow(myEvent.where, &whichWindow);
  3451.     if ((whichWindow == TextEditWindow) && (whichWindow != 0))
  3452.         DoEditMouseDown (code, whichWindow, &myEvent);
  3453.     else
  3454.     {
  3455.         switch (code)
  3456.         {
  3457.             case inMenuBar:
  3458.                 SetCursor(&qd.arrow);
  3459.                 UpdateMenus();
  3460.                 DoCommand(MenuSelect(myEvent.where));
  3461.                 break;
  3462.             case inSysWindow:
  3463.                 SystemClick(&myEvent, whichWindow);
  3464.                 break;
  3465.             case inGoAway:
  3466.                 if (TrackGoAway(whichWindow, myEvent.where))
  3467.                     ;
  3468.                 break;
  3469.             case inGrow:
  3470.                 if ((whichWindow == (WindowPtr)myp2window) && (myp2window))
  3471.                 {
  3472.                     p2w_DoGrow(myp2window, &myEvent);
  3473.                     get_WindowPos((WindowPtr)myp2window, &theWindowPos);
  3474.                     global_settings->statWind_pos = theWindowPos;
  3475.                 }
  3476.                 break;
  3477.             case inZoomIn:
  3478.             case inZoomOut:
  3479.                 if (TrackBox(whichWindow, myEvent.where, code))
  3480.                     ;
  3481.                 break;
  3482.             case inDrag:
  3483.                 DragWindow(whichWindow, myEvent.where, &dragBounds);
  3484.                 get_WindowPos(whichWindow, &theWindowPos);
  3485.                 if ((whichWindow == (WindowPtr)myp2window) && (myp2window))
  3486.                     global_settings->statWind_pos = theWindowPos;
  3487.                 if ((whichWindow == plot_window) && (plot_window))
  3488.                 {
  3489.                     global_settings->imageWind_pos = theWindowPos;
  3490.                     file_settings->imageWind_pos = theWindowPos;
  3491.                 }
  3492.                 break;
  3493.             case inContent:
  3494.                 if (whichWindow != FrontWindow())
  3495.                     SelectWindow(whichWindow);
  3496.                 else
  3497.                 {
  3498.                     if ((whichWindow == (WindowPtr)myp2window) && (myp2window))
  3499.                         p2w_DoContentClick(myp2window, &myEvent);
  3500.                     else
  3501.                     if (whichWindow == plot_window)
  3502.                     {
  3503.                         SetPort(whichWindow);
  3504.                         GlobalToLocal(&myEvent.where);
  3505.                         part = FindControl(myEvent.where, whichWindow, &whichControl);
  3506.                         /* perform window controls such as resizing or scrolling here */
  3507.                     }
  3508.                 }
  3509.                 break;
  3510.         }
  3511.     }
  3512. }
  3513.  
  3514. void DoKeyDown(void)
  3515. {
  3516.     char    theChar, theVirtualCode;
  3517.  
  3518.     theChar = myEvent.message & charCodeMask;
  3519.     theVirtualCode = (myEvent.message & keyCodeMask) >> 8;
  3520.  
  3521.     if (myEvent.modifiers & cmdKey)
  3522.     {
  3523.         UpdateMenus();
  3524.         DoCommand(MenuKey(theChar));
  3525.     }
  3526.     else
  3527.     {
  3528.         if (FrontWindow() == TextEditWindow)
  3529.         {
  3530.             switch (theVirtualCode)
  3531.             {
  3532.                 case 0x33:                /* delete */
  3533.                     if ((**TEH).selStart != (**TEH).selEnd)
  3534.                     {
  3535.                         support_undo("Delete", TRUE);
  3536.                         TEDelete(TEH);    /* delete a range */
  3537.                     }
  3538.                     else
  3539.                     {
  3540.                         support_undo_key();
  3541.                         TEKey(theChar, TEH); /* delete char */
  3542.                     }
  3543.                     dirty = 1;
  3544.                     AdjustText();
  3545.                     break;
  3546.                 case 0x73:                /* HOME */
  3547.                     SetCtlValue(vScroll, 0);
  3548.                     AdjustText();
  3549.                     break;
  3550.                 case 0x77:                /* END */
  3551.                     SetCtlValue(vScroll, (**TEH).teLength);
  3552.                     AdjustText();
  3553.                     break;
  3554.                 case 0x74:                /* PAGE UP */
  3555.                     ScrollProc(vScroll, inPageUp);
  3556.                     AdjustText();
  3557.                     break;
  3558.                 case 0x79:                /* PAGE DOWN */
  3559.                     ScrollProc(vScroll, inPageDown);
  3560.                     AdjustText();
  3561.                     break;
  3562.                 case 0x7A:                /* UNDO (F1) */
  3563.                     undo_text();
  3564.                     break;
  3565.                 case 0x78:                /* CUT (F2) */
  3566.                     support_undo("Cut", TRUE);
  3567.                     TECut(TEH);
  3568.                     AdjustText();
  3569.                     dirty = 1;
  3570.                     break;
  3571.                 case 0x63:                /* COPY (F3) */
  3572.                     TECopy(TEH);
  3573.                     break;
  3574.                 case 0x76:                /* PASTE (F4) */
  3575.                     support_undo("Paste", TRUE);
  3576.                     TEPaste(TEH);
  3577.                     AdjustText();
  3578.                     dirty = 1;
  3579.                     break;
  3580.                 
  3581.                 case 0x75:                /* del >x> */
  3582.                     if ((**TEH).selStart != (**TEH).selEnd)
  3583.                     {
  3584.                         support_undo("Delete", TRUE);
  3585.                         TEDelete(TEH);
  3586.                         AdjustText();
  3587.                     }
  3588.                     else
  3589.                     {   /* cursor-right then delete */
  3590.                         support_undo_key();
  3591.                         TEKey(0x1D, TEH); 
  3592.                         TEKey(0x08, TEH);
  3593.                     }
  3594.                     dirty = 1;
  3595.                     break;
  3596.  
  3597.                 case 0x1C:                /* Cursor keys, don't dirty the buffer or require undo */
  3598.                 case 0x1D:
  3599.                 case 0x1E:
  3600.                 case 0x1F:
  3601.                     TEKey(theChar, TEH);
  3602.                     ShowSelect();
  3603.                     break;
  3604.  
  3605.                 default:                /* all other keys */
  3606.                     support_undo_key();
  3607.                     TEKey(theChar, TEH);
  3608.                     dirty = 1;
  3609.                     ShowSelect();
  3610.             }
  3611.         }
  3612.     }            
  3613. }
  3614.  
  3615. void DoUpdateEvt(void)
  3616. {
  3617.     WindowPtr    wnd;
  3618.     
  3619.     wnd = (WindowPtr) myEvent.message;
  3620.     if ((wnd == TextEditWindow) && (TextEditWindow != 0))
  3621.         UpdateWindow (wnd);
  3622.     else
  3623.     if ((wnd == (WindowPtr) myp2window) && (myp2window))
  3624.         p2w_DoUpdate(myp2window);
  3625.     else
  3626.     {    /* update the display window */
  3627.         BeginUpdate(wnd);
  3628.         SetPort(wnd);
  3629.         if ( (wnd == plot_window) && (plot_window) )
  3630.         {
  3631.             SetPort(plot_window);
  3632.             paint_whole_window();
  3633.         }
  3634.         EndUpdate(wnd);
  3635.     }
  3636. }
  3637. void DoActivateEvt(void)
  3638. {
  3639.     if (((WindowPtr)myEvent.message == (WindowPtr)myp2window) && (myp2window))
  3640.         p2w_DoActivate(myp2window, myEvent.modifiers & 1);
  3641.     else
  3642.     if (myEvent.modifiers & 1)
  3643.         Activate((WindowPtr) myEvent.message);
  3644.     else
  3645.         Deactivate((WindowPtr) myEvent.message);
  3646. }
  3647.  
  3648. void DoApp4Evt(void)
  3649. {
  3650.     if (myEvent.message >> 24 == 1)
  3651.     {
  3652.         /* Update the background-friendliness flag upon Suspend/Resume */    
  3653.         MultiFriendly = global_settings->howMultiFriendly;    
  3654.         if (myEvent.message & 1)
  3655.         {
  3656.             backgrounding = 0;
  3657.             Activate(FrontWindow());
  3658.         }
  3659.         else
  3660.         {
  3661.             backgrounding = TRUE;
  3662.             Deactivate(FrontWindow());
  3663.             /* If in the background, back off on the rendering throttle some */    
  3664.             if (MultiFriendly > 2)
  3665.                 MultiFriendly -= (MultiFriendly >> 1);    
  3666.         }
  3667.         SetCursor(&qd.arrow);
  3668.     }
  3669. }
  3670.  
  3671. void DoHighLevelEvt(void)
  3672. {
  3673.     short i;
  3674.     if (myEvent.message == 'aevt'/*kCoreEventClass*/)
  3675.         i = AEProcessAppleEvent(&myEvent);
  3676.     /* AppleEvents are the only supported high level events */
  3677. }
  3678.  
  3679.  
  3680. void MacDawdle(void)
  3681. {
  3682. int evtresult;
  3683.     if (backgrounding == 0)
  3684.     {
  3685.         // Stuff that only gets done if we're in front.
  3686.         if (TextEditWindow)
  3687.         {
  3688.             SetPort(TextEditWindow);
  3689.             MaintainCursor();
  3690.             if (TEH)
  3691.                 TEIdle(TEH);
  3692.         }
  3693.     }
  3694.     if (WNEavailable)
  3695.     {
  3696.         if (run_flag)
  3697.             WaitNextEvent(everyEvent, &myEvent, 0, NULL);
  3698.         else
  3699.             {
  3700.                 SetEventMask(everyEvent);
  3701.                 WaitNextEvent(everyEvent, &myEvent, 10, NULL);
  3702.             }
  3703.     }
  3704.     else
  3705.     {
  3706.         SystemTask();
  3707.         evtresult = GetNextEvent(everyEvent, &myEvent);
  3708.     }
  3709.  
  3710.     switch (myEvent.what)
  3711.     {
  3712.         case mouseDown:        
  3713.                     if (startupScreen)
  3714.                         {
  3715.                             DisposDialog (startupScreen);
  3716.                             startupScreen = NULL;
  3717.                             startupMessageTime = 0;
  3718.                         }
  3719.                     DoMouseDown();
  3720.                     break;
  3721.         case keyDown:
  3722.         case autoKey: 
  3723.                 if (startupScreen)
  3724.                     {
  3725.                         DisposDialog (startupScreen);
  3726.                         startupScreen = NULL;
  3727.                         startupMessageTime = 0;
  3728.                     }
  3729.                     DoKeyDown(); 
  3730.                     break;
  3731.         case updateEvt:        DoUpdateEvt(); break;
  3732.         case activateEvt:    DoActivateEvt(); break;
  3733.         case app4Evt:        DoApp4Evt(); break;
  3734.         case kHighLevelEvent:            /* high level event */
  3735.                             DoHighLevelEvt(); break;
  3736. /*        case nullEvent:        DoNullEvt(); */
  3737.     }
  3738. }
  3739.  
  3740.  
  3741. void DialogDawdle(void)
  3742. {
  3743. int evtresult;
  3744. short isMyDialog;
  3745. char theChar;
  3746.     itemHit = 0;
  3747.     if (WNEavailable)
  3748.         WaitNextEvent(everyEvent, &myEvent, 15, NULL);
  3749.     else
  3750.         evtresult = GetNextEvent(everyEvent, &myEvent);
  3751.  
  3752.     isMyDialog = IsDialogEvent (&myEvent);
  3753.     if (isMyDialog)
  3754.         DialogSelect (&myEvent,&myDialog,&itemHit);
  3755.     else
  3756.     {
  3757.         itemHit = 0;
  3758.         switch (myEvent.what)
  3759.         {
  3760.             case mouseDown:
  3761.                                 DoMouseDown();
  3762.                                 break;
  3763.             case keyDown:        
  3764.                                 theChar = myEvent.message & charCodeMask;
  3765.                                 if (myEvent.modifiers & cmdKey)
  3766.                                     DoKeyDown();
  3767.                                 break;
  3768.             case updateEvt:        DoUpdateEvt(); break;
  3769.             case activateEvt:    DoActivateEvt(); break;
  3770.             case app4Evt:        DoApp4Evt(); break;
  3771.             case nullEvent:        
  3772.                                 break;
  3773.             case kHighLevelEvent:             /* high level event */
  3774.                                 DoHighLevelEvt(); break;
  3775.         }
  3776.     }
  3777. }
  3778.  
  3779.  
  3780. void exit_handler(void)
  3781. {
  3782.     delete_virtual();
  3783.     if (myp2window)    
  3784.         p2w_DisposeWindow(myp2window);    
  3785.     p2w_Terminate();
  3786.     if (fileResRefNum != -1)
  3787.         CloseResFile (fileResRefNum);
  3788.     if ((prefsRefNum != -1) && global_settings_h)
  3789.     {
  3790.         UseResFile(prefsRefNum);
  3791.         Write_Our_Prefs();
  3792.         UseResFile(ourRefNum);
  3793.         CloseResFile (prefsRefNum);
  3794.         prefsRefNum = -1;
  3795.     }
  3796.     if (gtheSCComponent != NULL)
  3797.     {
  3798.         CloseComponent(gtheSCComponent);
  3799.         gtheSCComponent = NULL;
  3800.     }
  3801.     quit_flag = 1;
  3802.     ExitToShell();
  3803. }
  3804.  
  3805.  
  3806. void unexpected_exit(void)
  3807. {
  3808.     if (quit_flag == 0)
  3809.     {
  3810.         if (global_settings_h)
  3811.         {    
  3812.             DisposeHandle((Handle) global_settings_h);
  3813.             global_settings_h = NULL;    
  3814.         }    
  3815.         if (plot_window)
  3816.         {
  3817.             SetPort(plot_window);
  3818.             paint_whole_window();
  3819.         }
  3820.         error_dialog(132);
  3821.         exit_handler();
  3822.     }
  3823. }
  3824.  
  3825. void notify_user(void)
  3826. {
  3827.     Handle the_snd_handle;
  3828.     OSErr myErr;
  3829.  
  3830. /* If the image rendered OK and shutdown was requested, then shut down. */
  3831.     if ((file_settings->request_shutdown)  &&  (rendered_OK))
  3832.     {
  3833.         saveOutputFile(false);  /* write PICT file with current name.PICT */
  3834.         dispose_virtual();        /* close virtual file */
  3835.         if (AppleEvents_Available)
  3836.             SendQuit();
  3837.         else
  3838.             ShutDwnPower();
  3839.     }
  3840.     else
  3841.         do_notify = TRUE;
  3842.  
  3843. /* Play sound effect if in background, to get everyone's attention. */
  3844.     if (backgrounding)
  3845.     {
  3846.         the_snd_handle = GetNamedResource('snd ',"\pFileDone");
  3847.         if (the_snd_handle)
  3848.             myErr = SndPlay(NULL, the_snd_handle, TRUE);
  3849.     }
  3850. }
  3851.  
  3852.  
  3853. main()
  3854. {
  3855.     long        stk_size, start_ticks;
  3856.     int            i;
  3857.     Handle        h;
  3858.     CTabHandle    ctH;
  3859.     SysEnvRec    theWorld;
  3860.     OSErr        anError;
  3861.     StringPtr    errStr;    
  3862.     Rect        p2wRect;    
  3863.  
  3864. #ifdef applec
  3865.     UnloadSeg((Ptr) _DataInit);
  3866. #endif applec
  3867.  
  3868.     ourRefNum = CurResFile();
  3869.     
  3870.     /* Allocate more memory for stack. */
  3871.     h = Get1Resource('CNFG', 128);
  3872.     if (h)
  3873.     {
  3874.         stk_size = ** ((long **) h);
  3875.         ReleaseResource(h);
  3876.     }
  3877.     else
  3878.         stk_size = 40000;    /* a reasonable stack limit? */
  3879.     SetApplLimit(GetApplLimit() - stk_size);
  3880.     MaxApplZone();
  3881.  
  3882.     /* give us some master pointer blocks ahead of time, to reduce later memfrag */
  3883.     for (i=0; i<10; i++)
  3884.         MoreMasters();
  3885.  
  3886.     /* Register an exit handler */
  3887.     atexit(unexpected_exit);
  3888.     /* Initialize toolbox managers. */
  3889.     InitGraf(&qd.thePort);
  3890.     InitFonts();
  3891.     InitWindows();
  3892.     InitMenus();
  3893.     TEInit();
  3894.     InitDialogs(NULL);
  3895.     InitCursor();
  3896.     SetCursor(&qd.arrow);
  3897.     i=EventAvail(0, &myEvent);
  3898.     i=EventAvail(0, &myEvent);
  3899.     i=EventAvail(0, &myEvent);
  3900.  
  3901.     /* pre-allocate spare RAM for dialogs, which tend to pop up for out-of-memory conditions. */
  3902.     extra_dialog_RAM = NewHandle(reserveMemSize);
  3903.     prev_upd_plot = myEvent.when;
  3904.     
  3905.     /* Check if the necessary hard- & software is present. */
  3906.     errStr = NULL;    
  3907.     SysEnvirons(1, &theWorld);
  3908.  
  3909.     WNEavailable = trapAvailable(_WaitNextEvent, OSTrap, &theWorld);
  3910.     Gestalt_Available = true;
  3911.     qd32_Available = trapAvailable(_QD32Trap, ToolTrap, &theWorld);
  3912.  
  3913.     if (theWorld.processor < env68020)    
  3914.         errStr = "\pThis software requires a 68020 or better CPU.";    
  3915.     if (!theWorld.hasFPU)    
  3916.         errStr = "\pThis software requires a Floating Point Unit.";    
  3917.     if (theWorld.systemVersion < 0x0604)    
  3918.         errStr = "\pThis software requires System 6.0.4 or better";    
  3919.     if (!qd32_Available)                                
  3920.         errStr = "\pThis software requires 32 Bit Quickdraw";
  3921.  
  3922.     if (errStr)    
  3923.     {
  3924.         ParamText(errStr, "", "", "");    
  3925.         StopAlert(129, NULL);
  3926.         exit_handler();
  3927.     }
  3928.  
  3929.     /* set up bounds for window dragging (multiple/big monitors) */
  3930.     SetRect(&dragBounds, -32000, -32000, 32000, 32000);
  3931.  
  3932.     /* display splash screen early on, while app gets set up */
  3933.     startupMessageTime = TICKS;
  3934.     startupScreen = GetNewDialog(138, NULL, (WindowPtr) -1);
  3935.     if (startupScreen == NULL)
  3936.         startupMessageTime = 0;
  3937.     else
  3938.     {
  3939.         Str31    appVers, compilerName;
  3940.         GetAppVersionPString(1, appVers);
  3941.         GetCompilerNamePString(compilerName);
  3942.         ParamText(appVers, compilerName, "", "");
  3943.         DrawDialog(startupScreen);
  3944.     }
  3945.  
  3946.     /* See if the image compression manager (QuickTime to the Rest Of Us) is installed. */
  3947.     ImageCompressionMgrAvailable = false;
  3948.     if (Gestalt_Available)
  3949.     {
  3950.         long    gestaltResponse;
  3951.         if (Gestalt(gestaltCompressionMgr, &gestaltResponse) == noErr)
  3952.             if (gestaltResponse >= 15)
  3953.             {
  3954.                 /* Install and open the standard compression dialog component. */
  3955.                 gtheSCComponent = OpenStdCompression();
  3956.                 if (gtheSCComponent != NULL)
  3957.                 {
  3958.                     ImageCompressionMgrAvailable = true;
  3959.                     /*    Initial defaults for SC compression dialog. */    
  3960.                     gSCDialogParams.flags = 0;
  3961.                     gSCDialogParams.theCodecType = 'jpeg';
  3962.                     gSCDialogParams.theCodec = anyCodec;
  3963.                     gSCDialogParams.spatialQuality = codecNormalQuality;
  3964.                     gSCDialogParams.temporalQuality = 0;
  3965.                     gSCDialogParams.depth = 32;
  3966.                 }
  3967.             }
  3968.     }
  3969.  
  3970.  
  3971.     /* Set up menus. */
  3972.     for (i = 1; i <= highest_menu; i++)
  3973.     {
  3974.         myMenus[i] = GetMenu(i + 127);
  3975.         if (myMenus[i] == 0) exit_handler();
  3976.     }
  3977.     for (i = 1; i <= highest_submenu; i++)
  3978.     {
  3979.         mySubMenus[i] = GetMenu(i + 199);
  3980.         if (mySubMenus[i] == 0) exit_handler();
  3981.     }
  3982.     AddResMenu(myMenus[1], 'DRVR');
  3983.     for (i = 1; i <= highest_menu; i++)
  3984.         InsertMenu(myMenus[i], 0);
  3985.     for (i = 1; i <= highest_submenu; i++)
  3986.         InsertMenu(mySubMenus[i], -1);
  3987.     DrawMenuBar();
  3988.  
  3989.  
  3990.     GetPreferences();
  3991.  
  3992.     /* refresh splash screen in case previous dialogs walked on it */
  3993.     if (startupScreen)
  3994.         DrawDialog(startupScreen);
  3995.  
  3996.     /* create a default file settings record now. */
  3997.     file_settings_h = (prefs_hdl_t) NewHandle(sizeof(prefs_rec_t)); 
  3998.     MoveHHi((Handle) file_settings_h);
  3999.     HLock((Handle) file_settings_h);
  4000.     file_settings = *file_settings_h;
  4001.     memcpy (file_settings, global_settings, sizeof(prefs_rec_t)); 
  4002.  
  4003.     /* Re-default to the application's resource file for other functions like dialogs. */
  4004.     UseResFile(ourRefNum);
  4005.     *theFileName = 0;
  4006.     fileResRefNum = -1;
  4007.  
  4008.     /* Set up the status output window */
  4009.     anError = p2w_Init();
  4010.     if (!anError)
  4011.     {
  4012.         p2wRect = global_settings->statWind_pos;
  4013.         myp2window = p2w_NewWindow(&p2wRect, "\pPOV Status", false, monaco, 9, &anError);
  4014.     }
  4015.     if (anError)
  4016.     {
  4017.         error_dialog(kdlog_P2W_INIT_ERROR);
  4018.         exit_handler();
  4019.     }
  4020.  
  4021.     /* Set up offscreen pixmap. */
  4022.     ctH = (CTabHandle) NewHandle(sizeof(ColorTable));
  4023.     (*ctH)->ctSeed = 24;
  4024.     (*ctH)->ctFlags = 0;
  4025.     (*ctH)->ctSize = 0;
  4026.     pm = (PixMapHandle) NewHandle(sizeof(PixMap));
  4027.     (*pm)->pmVersion = 0;
  4028.     (*pm)->packType = 0;
  4029.     (*pm)->packSize = 0;
  4030.     (*pm)->hRes = 0x480000;
  4031.     (*pm)->vRes = 0x480000;
  4032.     (*pm)->pixelType = RGBDirect;
  4033.     (*pm)->pixelSize = 32;
  4034.     (*pm)->cmpCount = 3;
  4035.     (*pm)->cmpSize = 8;
  4036.     (*pm)->planeBytes = 0;
  4037.     (*pm)->pmTable = ctH;
  4038.     (*pm)->pmReserved = 0;
  4039.  
  4040.     init_undo_system();
  4041.     init_redo_system();
  4042.     Install_AppleEvents();
  4043.  
  4044.     maxmalloc = FreeMem() / 210L;
  4045.     GarbagePile = (long *) NewPtr(maxmalloc*4L + 8L);
  4046.     RecycledPile = (long *) NewPtr(maxmalloc*4L + 8L);
  4047.     if ((GarbagePile == 0) || (RecycledPile == 0))
  4048.     {    StopAlert(129, NULL);
  4049.         exit_handler();    }
  4050.     *GarbagePile = 0;        /* unmark first item on list */
  4051.     *RecycledPile = 0;
  4052.     mallocCount = 0;
  4053.     mfreeCount = 0;
  4054.     rendered_OK = 1;
  4055.  
  4056.     /* Figure out how much time to give other processes */
  4057.     MultiFriendly = global_settings->howMultiFriendly;
  4058.  
  4059.     main_init();        /* for text editor */
  4060.     /* Main event loop, sort of. */
  4061.     while (!quit_flag)
  4062.     {
  4063.         MacDawdle();
  4064.  
  4065. /* Check for notification of finished trace */
  4066.         if (do_notify && (backgrounding == 0))
  4067.         {
  4068.             for (i=1; i<3; i++)
  4069.                 MacDawdle();        /* get update events */
  4070.             if (do_notify)
  4071.                 error_dialog (143 - rendered_OK);
  4072.             do_notify = 0;
  4073.         }
  4074.  
  4075. /* Check for timeout on startup message.  Remove the dialog after timeout. */
  4076.         if (startupScreen)
  4077.             if ( (startupMessageTime) && ((startupMessageTime+420) < TICKS) )
  4078.             {
  4079.                 DisposDialog (startupScreen);
  4080.                 startupScreen = NULL;
  4081.                 startupMessageTime = 0;
  4082.             }
  4083.  
  4084. /* Update current settings for the magnification factor for display window */
  4085.         display_magniFactor = file_settings->magniFactor;
  4086.         if (display_magniFactor == 5)
  4087.             display_magniFactor = 8;
  4088.  
  4089.         if (run_flag)
  4090.         {
  4091.             Size    toGrow;
  4092.             if (file_settings->request_shutdown)
  4093.                     error_dialog (148);
  4094.             /* open some heap space just before we start */
  4095.             MaxMem(&toGrow);
  4096.             start_ticks = TICKS;
  4097.  
  4098. #ifdef NEEDS_PERF            
  4099.             printf("Starting performance analysis\n");
  4100.             startPerf();
  4101. #endif NEEDS_PERF            
  4102.  
  4103.             call_main(ARGC, ARGV);
  4104.  
  4105. #ifdef NEEDS_PERF            
  4106.             stopPerf();
  4107.             printf("Completed performance analysis\n");
  4108. #endif NEEDS_PERF
  4109.  
  4110. /* if it was a long, uninterrupted trace, OR if POV is in the background, OR if shutdown
  4111.    was requested at completion, OR there was an error, call the notification procedure. */
  4112.             if ( 
  4113.                 (Stop_Flag == 0) &&
  4114.                 (((TICKS - start_ticks) > 7200) || backgrounding 
  4115.                     || file_settings->request_shutdown || (rendered_OK == 0))
  4116.                )
  4117.                 notify_user();
  4118.         }
  4119.         else
  4120.             if (quit_flag) break;
  4121.     }
  4122.     
  4123.     /* Clean up & exit. */
  4124.     exit_handler();
  4125. }
  4126.